summaryrefslogtreecommitdiffstats
path: root/src/libsystemd
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/libsystemd
parentAdding upstream version 255.5. (diff)
downloadsystemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz
systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/libsystemd')
-rw-r--r--src/libsystemd/libsystemd.sym9
-rw-r--r--src/libsystemd/meson.build8
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.c3
-rw-r--r--src/libsystemd/sd-bus/bus-common-errors.h3
-rw-r--r--src/libsystemd/sd-bus/bus-container.c2
-rw-r--r--src/libsystemd/sd-bus/bus-control.c139
-rw-r--r--src/libsystemd/sd-bus/bus-convenience.c38
-rw-r--r--src/libsystemd/sd-bus/bus-creds.c149
-rw-r--r--src/libsystemd/sd-bus/bus-creds.h18
-rw-r--r--src/libsystemd/sd-bus/bus-dump.c2
-rw-r--r--src/libsystemd/sd-bus/bus-internal.h4
-rw-r--r--src/libsystemd/sd-bus/bus-message.c4
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c2
-rw-r--r--src/libsystemd/sd-bus/bus-socket.c112
-rw-r--r--src/libsystemd/sd-bus/bus-track.c2
-rw-r--r--src/libsystemd/sd-bus/sd-bus.c102
-rw-r--r--src/libsystemd/sd-bus/test-bus-chat.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-cleanup.c2
-rw-r--r--src/libsystemd/sd-bus/test-bus-creds.c24
-rw-r--r--src/libsystemd/sd-bus/test-bus-error.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-marshal.c4
-rw-r--r--src/libsystemd/sd-bus/test-bus-objects.c3
-rw-r--r--src/libsystemd/sd-bus/test-bus-peersockaddr.c55
-rw-r--r--src/libsystemd/sd-daemon/sd-daemon.c75
-rw-r--r--src/libsystemd/sd-device/device-enumerator.c10
-rw-r--r--src/libsystemd/sd-device/device-monitor.c23
-rw-r--r--src/libsystemd/sd-device/device-private.c125
-rw-r--r--src/libsystemd/sd-device/device-private.h3
-rw-r--r--src/libsystemd/sd-device/device-util.c39
-rw-r--r--src/libsystemd/sd-device/device-util.h13
-rw-r--r--src/libsystemd/sd-device/sd-device.c113
-rw-r--r--src/libsystemd/sd-device/test-device-util.c78
-rw-r--r--src/libsystemd/sd-device/test-sd-device-monitor.c4
-rw-r--r--src/libsystemd/sd-device/test-sd-device-thread.c3
-rw-r--r--src/libsystemd/sd-device/test-sd-device.c10
-rw-r--r--src/libsystemd/sd-event/event-source.h3
-rw-r--r--src/libsystemd/sd-event/event-util.c26
-rw-r--r--src/libsystemd/sd-event/event-util.h6
-rw-r--r--src/libsystemd/sd-event/sd-event.c62
-rw-r--r--src/libsystemd/sd-event/test-event.c48
-rw-r--r--src/libsystemd/sd-hwdb/sd-hwdb.c8
-rw-r--r--src/libsystemd/sd-id128/id128-util.c82
-rw-r--r--src/libsystemd/sd-id128/id128-util.h3
-rw-r--r--src/libsystemd/sd-id128/sd-id128.c52
-rw-r--r--src/libsystemd/sd-journal/catalog.c91
-rw-r--r--src/libsystemd/sd-journal/catalog.h2
-rw-r--r--src/libsystemd/sd-journal/fsprg.c208
-rw-r--r--src/libsystemd/sd-journal/fsprg.h25
-rw-r--r--src/libsystemd/sd-journal/journal-authenticate.c68
-rw-r--r--src/libsystemd/sd-journal/journal-file.c104
-rw-r--r--src/libsystemd/sd-journal/journal-file.h4
-rw-r--r--src/libsystemd/sd-journal/journal-internal.h18
-rw-r--r--src/libsystemd/sd-journal/journal-send.c27
-rw-r--r--src/libsystemd/sd-journal/journal-send.h17
-rw-r--r--src/libsystemd/sd-journal/journal-verify.c3
-rw-r--r--src/libsystemd/sd-journal/sd-journal.c566
-rw-r--r--src/libsystemd/sd-journal/test-journal-append.c4
-rw-r--r--src/libsystemd/sd-journal/test-journal-enum.c6
-rw-r--r--src/libsystemd/sd-journal/test-journal-flush.c92
-rw-r--r--src/libsystemd/sd-journal/test-journal-init.c11
-rw-r--r--src/libsystemd/sd-journal/test-journal-interleaving.c279
-rw-r--r--src/libsystemd/sd-journal/test-journal-match.c44
-rw-r--r--src/libsystemd/sd-journal/test-journal-stream.c20
-rw-r--r--src/libsystemd/sd-journal/test-journal-verify.c6
-rw-r--r--src/libsystemd/sd-journal/test-journal.c12
-rw-r--r--src/libsystemd/sd-login/sd-login.c7
-rw-r--r--src/libsystemd/sd-login/test-login.c17
-rw-r--r--src/libsystemd/sd-netlink/netlink-message-rtnl.c41
-rw-r--r--src/libsystemd/sd-netlink/netlink-message.c29
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-genl.c1
-rw-r--r--src/libsystemd/sd-netlink/netlink-types-rtnl.c13
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.c421
-rw-r--r--src/libsystemd/sd-netlink/netlink-util.h56
-rw-r--r--src/libsystemd/sd-netlink/sd-netlink.c8
-rw-r--r--src/libsystemd/sd-netlink/test-netlink.c14
-rw-r--r--src/libsystemd/sd-network/network-util.c59
-rw-r--r--src/libsystemd/sd-network/network-util.h30
-rw-r--r--src/libsystemd/sd-network/sd-network.c2
-rw-r--r--src/libsystemd/sd-path/sd-path.c46
79 files changed, 2494 insertions, 1335 deletions
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 4113920..78b4453 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -834,3 +834,12 @@ global:
sd_id128_get_app_specific;
sd_device_enumerator_add_match_property_required;
} LIBSYSTEMD_254;
+
+LIBSYSTEMD_256 {
+global:
+ sd_bus_creds_get_pidfd_dup;
+ sd_bus_creds_new_from_pidfd;
+ sd_id128_get_invocation_app_specific;
+ sd_journal_stream_fd_with_namespace;
+ sd_event_source_get_inotify_path;
+} LIBSYSTEMD_255;
diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build
index 5d18f97..6d4337d 100644
--- a/src/libsystemd/meson.build
+++ b/src/libsystemd/meson.build
@@ -118,8 +118,7 @@ libsystemd_static = static_library(
libsystemd_sources,
include_directories : libsystemd_includes,
c_args : libsystemd_c_args,
- link_with : [libbasic,
- libbasic_compress],
+ link_with : [libbasic],
dependencies : [threads,
librt,
userspace],
@@ -159,6 +158,10 @@ libsystemd_tests += [
'sources' : files('sd-journal/test-journal-enum.c'),
'timeout' : 360,
},
+ {
+ 'sources' : files('sd-event/test-event.c'),
+ 'timeout' : 120,
+ }
]
############################################################
@@ -171,7 +174,6 @@ simple_tests += files(
'sd-device/test-device-util.c',
'sd-device/test-sd-device-monitor.c',
'sd-device/test-sd-device.c',
- 'sd-event/test-event.c',
'sd-journal/test-journal-flush.c',
'sd-journal/test-journal-interleaving.c',
'sd-journal/test-journal-stream.c',
diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c
index df26fd7..de12ec5 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.c
+++ b/src/libsystemd/sd-bus/bus-common-errors.c
@@ -105,11 +105,13 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NO_HARDWARE_SERIAL, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_FILE_IS_PROTECTED, EACCES),
SD_BUS_ERROR_MAP(BUS_ERROR_READ_ONLY_FILESYSTEM, EROFS),
SD_BUS_ERROR_MAP(BUS_ERROR_SPEED_METER_INACTIVE, EOPNOTSUPP),
SD_BUS_ERROR_MAP(BUS_ERROR_UNMANAGED_INTERFACE, EOPNOTSUPP),
+ SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_ALREADY_RELOADING, EBUSY),
SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_HOME, EEXIST),
SD_BUS_ERROR_MAP(BUS_ERROR_UID_IN_USE, EEXIST),
@@ -146,6 +148,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = {
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_CANT_AUTHENTICATE, EKEYREVOKED),
SD_BUS_ERROR_MAP(BUS_ERROR_HOME_IN_USE, EADDRINUSE),
SD_BUS_ERROR_MAP(BUS_ERROR_REBALANCE_NOT_NEEDED, EALREADY),
+ SD_BUS_ERROR_MAP(BUS_ERROR_HOME_NOT_REFERENCED, EBADR),
SD_BUS_ERROR_MAP_END
};
diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h
index 3a0eef4..94dc85d 100644
--- a/src/libsystemd/sd-bus/bus-common-errors.h
+++ b/src/libsystemd/sd-bus/bus-common-errors.h
@@ -106,11 +106,13 @@
#define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress"
#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID"
+#define BUS_ERROR_NO_HARDWARE_SERIAL "org.freedesktop.hostname1.NoHardwareSerial"
#define BUS_ERROR_FILE_IS_PROTECTED "org.freedesktop.hostname1.FileIsProtected"
#define BUS_ERROR_READ_ONLY_FILESYSTEM "org.freedesktop.hostname1.ReadOnlyFilesystem"
#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive"
#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface"
+#define BUS_ERROR_NETWORK_ALREADY_RELOADING "org.freedesktop.network1.AlreadyReloading"
#define BUS_ERROR_NO_SUCH_HOME "org.freedesktop.home1.NoSuchHome"
#define BUS_ERROR_UID_IN_USE "org.freedesktop.home1.UIDInUse"
@@ -151,5 +153,6 @@
#define BUS_ERROR_HOME_CANT_AUTHENTICATE "org.freedesktop.home1.HomeCantAuthenticate"
#define BUS_ERROR_HOME_IN_USE "org.freedesktop.home1.HomeInUse"
#define BUS_ERROR_REBALANCE_NOT_NEEDED "org.freedesktop.home1.RebalanceNotNeeded"
+#define BUS_ERROR_HOME_NOT_REFERENCED "org.freedesktop.home1.HomeNotReferenced"
BUS_ERROR_MAP_ELF_USE(bus_common_errors);
diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c
index 4146a6e..2eca82b 100644
--- a/src/libsystemd/sd-bus/bus-container.c
+++ b/src/libsystemd/sd-bus/bus-container.c
@@ -34,7 +34,7 @@ int bus_container_connect_socket(sd_bus *b) {
log_debug("sd-bus: connecting bus%s%s to namespace of PID "PID_FMT"...",
b->description ? " " : "", strempty(b->description), b->nspid);
- r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, NULL, &usernsfd, &rootfd);
+ r = namespace_open(b->nspid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd);
if (r < 0)
return log_debug_errno(r, "Failed to open namespace of PID "PID_FMT": %m", b->nspid);
diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c
index 1355e41..c420584 100644
--- a/src/libsystemd/sd-bus/bus-control.c
+++ b/src/libsystemd/sd-bus/bus-control.c
@@ -14,6 +14,7 @@
#include "bus-internal.h"
#include "bus-message.h"
#include "capability-util.h"
+#include "fd-util.h"
#include "process-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -430,7 +431,6 @@ _public_ int sd_bus_get_name_creds(
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
const char *unique;
- pid_t pid = 0;
int r;
assert_return(bus, -EINVAL);
@@ -483,8 +483,9 @@ _public_ int sd_bus_get_name_creds(
}
if (mask != 0) {
+ bool need_pid, need_uid, need_gids, need_selinux, need_separate_calls, need_pidfd, need_augment;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- bool need_pid, need_uid, need_selinux, need_separate_calls;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
c = bus_creds_new();
if (!c)
@@ -498,20 +499,25 @@ _public_ int sd_bus_get_name_creds(
c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
}
- need_pid = (mask & SD_BUS_CREDS_PID) ||
- ((mask & SD_BUS_CREDS_AUGMENT) &&
- (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
- SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
- SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
- SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
- SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
- SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
- SD_BUS_CREDS_SELINUX_CONTEXT|
- SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
+ need_augment =
+ (mask & SD_BUS_CREDS_AUGMENT) &&
+ (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+ SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+ SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
+ SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+ SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+ SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+ SD_BUS_CREDS_SELINUX_CONTEXT|
+ SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID|
+ SD_BUS_CREDS_PIDFD));
+
+ need_pid = (mask & SD_BUS_CREDS_PID) || need_augment;
need_uid = mask & SD_BUS_CREDS_EUID;
+ need_gids = mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
+ need_pidfd = (mask & SD_BUS_CREDS_PIDFD) || need_augment;
- if (need_pid + need_uid + need_selinux > 1) {
+ if (need_pid + need_uid + need_selinux + need_pidfd + need_gids > 1) {
/* If we need more than one of the credentials, then use GetConnectionCredentials() */
@@ -572,7 +578,9 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- pid = p;
+ if (!pidref_is_set(&pidref))
+ pidref = PIDREF_MAKE_FROM_PID(p);
+
if (mask & SD_BUS_CREDS_PID) {
c->pid = p;
c->mask |= SD_BUS_CREDS_PID;
@@ -599,6 +607,69 @@ _public_ int sd_bus_get_name_creds(
r = sd_bus_message_exit_container(reply);
if (r < 0)
return r;
+ } else if (need_pidfd && streq(m, "ProcessFD")) {
+ int fd;
+
+ r = sd_bus_message_read(reply, "v", "h", &fd);
+ if (r < 0)
+ return r;
+
+ pidref_done(&pidref);
+ r = pidref_set_pidfd(&pidref, fd);
+ if (r < 0)
+ return r;
+
+ if (mask & SD_BUS_CREDS_PIDFD) {
+ fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (fd < 0)
+ return -errno;
+
+ close_and_replace(c->pidfd, fd);
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+ } else if (need_gids && streq(m, "UnixGroupIDs")) {
+
+ /* Note that D-Bus actually only gives us a combined list of
+ * primary gid and supplementary gids. And we don't know
+ * which one the primary one is. We'll take the whole shebang
+ * hence and use it as the supplementary group list, and not
+ * initialize the primary gid field. This is slightly
+ * incorrect of course, but only slightly, as in effect if
+ * the primary gid is also listed in the supplementary gid
+ * it has zero effect. */
+
+ r = sd_bus_message_enter_container(reply, 'v', "au");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_enter_container(reply, 'a', "u");
+ if (r < 0)
+ return r;
+
+ for (;;) {
+ uint32_t u;
+
+ r = sd_bus_message_read(reply, "u", &u);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ break;
+
+ if (!GREEDY_REALLOC(c->supplementary_gids, c->n_supplementary_gids+1))
+ return -ENOMEM;
+
+ c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) u;
+ }
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(reply);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
} else {
r = sd_bus_message_skip(reply, "v");
if (r < 0)
@@ -614,7 +685,7 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- if (need_pid && pid == 0)
+ if (need_pid && !pidref_is_set(&pidref))
return -EPROTO;
}
@@ -642,7 +713,9 @@ _public_ int sd_bus_get_name_creds(
if (r < 0)
return r;
- pid = u;
+ if (!pidref_is_set(&pidref))
+ pidref = PIDREF_MAKE_FROM_PID(u);
+
if (mask & SD_BUS_CREDS_PID) {
c->pid = u;
c->mask |= SD_BUS_CREDS_PID;
@@ -710,9 +783,11 @@ _public_ int sd_bus_get_name_creds(
}
}
- r = bus_creds_add_more(c, mask, pid, 0);
- if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
- return r;
+ if (pidref_is_set(&pidref)) {
+ r = bus_creds_add_more(c, mask, &pidref, 0);
+ if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
+ return r;
+ }
}
if (creds)
@@ -765,8 +840,8 @@ not_found:
_public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
- bool do_label, do_groups, do_sockaddr_peer;
- pid_t pid = 0;
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ bool do_label, do_groups, do_sockaddr_peer, do_pidfd;
int r;
assert_return(bus, -EINVAL);
@@ -786,9 +861,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
do_sockaddr_peer = bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1 &&
bus->sockaddr_peer.sa.sa_family == AF_UNIX &&
bus->sockaddr_peer.un.sun_path[0] == 0;
+ do_pidfd = bus->pidfd >= 0 && (mask & SD_BUS_CREDS_PIDFD);
/* Avoid allocating anything if we have no chance of returning useful data */
- if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer)
+ if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer && !do_pidfd)
return -ENODATA;
c = bus_creds_new();
@@ -797,8 +873,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
if (bus->ucred_valid) {
if (pid_is_valid(bus->ucred.pid)) {
- pid = c->pid = bus->ucred.pid;
+ c->pid = bus->ucred.pid;
c->mask |= SD_BUS_CREDS_PID & mask;
+
+ pidref = PIDREF_MAKE_FROM_PID(c->pid);
}
if (uid_is_valid(bus->ucred.uid)) {
@@ -859,7 +937,20 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
}
}
- r = bus_creds_add_more(c, mask, pid, 0);
+ if (do_pidfd) {
+ c->pidfd = fcntl(bus->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (c->pidfd < 0)
+ return -errno;
+
+ pidref_done(&pidref);
+ r = pidref_set_pidfd(&pidref, bus->pidfd);
+ if (r < 0)
+ return r;
+
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
+ r = bus_creds_add_more(c, mask, &pidref, 0);
if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r;
diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c
index 989e577..14d8073 100644
--- a/src/libsystemd/sd-bus/bus-convenience.c
+++ b/src/libsystemd/sd-bus/bus-convenience.c
@@ -640,8 +640,8 @@ _public_ int sd_bus_set_property(
}
_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **ret) {
+ uint64_t missing;
sd_bus_creds *c;
- int r;
assert_return(call, -EINVAL);
assert_return(call->sealed, -EPERM);
@@ -653,36 +653,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
return -ENOTCONN;
c = sd_bus_message_get_creds(call);
-
- /* All data we need? */
- if (c && (mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask) == 0) {
+ if (c)
+ missing = mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask;
+ else
+ missing = mask & ~SD_BUS_CREDS_AUGMENT;
+ if (missing == 0) { /* All data we need? */
*ret = sd_bus_creds_ref(c);
return 0;
}
- /* No data passed? Or not enough data passed to retrieve the missing bits? */
- if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
- /* We couldn't read anything from the call, let's try
- * to get it from the sender or peer. */
-
- if (call->sender)
- /* There's a sender, but the creds are missing. */
- return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
- else
- /* There's no sender. For direct connections
- * the credentials of the AF_UNIX peer matter,
- * which may be queried via sd_bus_get_owner_creds(). */
- return sd_bus_get_owner_creds(call->bus, mask, ret);
- }
-
- r = bus_creds_extend_by_pid(c, mask, ret);
- if (r == -ESRCH) {
- /* Process doesn't exist anymore? propagate the few things we have */
- *ret = sd_bus_creds_ref(c);
- return 0;
- }
+ /* There's a sender, use that */
+ if (call->sender && call->bus->bus_client)
+ return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
- return r;
+ /* There's no sender. For direct connections the credentials of the AF_UNIX peer matter, which may be
+ * queried via sd_bus_get_owner_creds(). */
+ return sd_bus_get_owner_creds(call->bus, mask, ret);
}
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c
index c6d8caa..adbdeaa 100644
--- a/src/libsystemd/sd-bus/bus-creds.c
+++ b/src/libsystemd/sd-bus/bus-creds.c
@@ -53,6 +53,8 @@ void bus_creds_done(sd_bus_creds *c) {
* below. */
strv_free(c->cmdline_array);
+
+ safe_close(c->pidfd);
}
_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
@@ -129,46 +131,72 @@ _public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
sd_bus_creds* bus_creds_new(void) {
sd_bus_creds *c;
- c = new0(sd_bus_creds, 1);
+ c = new(sd_bus_creds, 1);
if (!c)
return NULL;
- c->allocated = true;
- c->n_ref = 1;
+ *c = (sd_bus_creds) {
+ .allocated = true,
+ .n_ref = 1,
+ SD_BUS_CREDS_INIT_FIELDS,
+ };
+
return c;
}
-_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+static int bus_creds_new_from_pidref(sd_bus_creds **ret, PidRef *pidref, uint64_t mask) {
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
int r;
- assert_return(pid >= 0, -EINVAL);
assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL);
- if (pid == 0)
- pid = getpid_cached();
-
c = bus_creds_new();
if (!c)
return -ENOMEM;
- r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
+ r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pidref, 0);
if (r < 0)
return r;
- /* Check if the process existed at all, in case we haven't
- * figured that out already */
- r = pid_is_alive(pid);
+ r = pidref_verify(pidref);
if (r < 0)
return r;
- if (r == 0)
- return -ESRCH;
*ret = TAKE_PTR(c);
return 0;
}
+_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
+
+ assert_return(pid >= 0, -EINVAL);
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+
+ r = pidref_set_pid(&pidref, pid);
+ if (r < 0)
+ return r;
+
+ return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
+_public_ int sd_bus_creds_new_from_pidfd(sd_bus_creds **ret, int pidfd, uint64_t mask) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+ int r;
+
+ assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+ assert_return(ret, -EINVAL);
+ assert_return(pidfd >= 0, -EBADF);
+
+ r = pidref_set_pidfd(&pidref, pidfd);
+ if (r < 0)
+ return r;
+
+ return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
assert_return(c, -EINVAL);
assert_return(uid, -EINVAL);
@@ -280,6 +308,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
return 0;
}
+_public_ int sd_bus_creds_get_pidfd_dup(sd_bus_creds *c, int *ret_fd) {
+ _cleanup_close_ int copy = -EBADF;
+
+ assert_return(c, -EINVAL);
+ assert_return(ret_fd, -EINVAL);
+
+ if (!(c->mask & SD_BUS_CREDS_PIDFD))
+ return -ENODATA;
+
+ copy = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ *ret_fd = TAKE_FD(copy);
+ return 0;
+}
+
_public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
assert_return(c, -EINVAL);
assert_return(ppid, -EINVAL);
@@ -731,7 +776,7 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
return -ENOMEM;
}
- for (i = 0; i < sz; i ++) {
+ for (i = 0; i < sz; i++) {
uint32_t v = 0;
for (j = 0; j < 8; ++j) {
@@ -750,7 +795,8 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
return 0;
}
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid) {
+ _cleanup_(pidref_done) PidRef pidref_buf = PIDREF_NULL;
uint64_t missing;
int r;
@@ -761,12 +807,26 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
return 0;
/* Try to retrieve PID from creds if it wasn't passed to us */
- if (pid > 0) {
- c->pid = pid;
+ if (pidref_is_set(pidref)) {
+ if ((c->mask & SD_BUS_CREDS_PID) && c->pid != pidref->pid) /* Insist that things match if already set */
+ return -EBUSY;
+
+ c->pid = pidref->pid;
c->mask |= SD_BUS_CREDS_PID;
- } else if (c->mask & SD_BUS_CREDS_PID)
- pid = c->pid;
- else
+ } else if (c->mask & SD_BUS_CREDS_PIDFD) {
+ r = pidref_set_pidfd(&pidref_buf, c->pidfd);
+ if (r < 0)
+ return r;
+
+ pidref = &pidref_buf;
+
+ } else if (c->mask & SD_BUS_CREDS_PID) {
+ r = pidref_set_pid(&pidref_buf, c->pid);
+ if (r < 0)
+ return r;
+
+ pidref = &pidref_buf;
+ } else
/* Without pid we cannot do much... */
return 0;
@@ -784,6 +844,14 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->mask |= SD_BUS_CREDS_TID;
}
+ if ((missing & SD_BUS_CREDS_PIDFD) && pidref->fd >= 0) {
+ c->pidfd = fcntl(pidref->fd, F_DUPFD_CLOEXEC, 3);
+ if (c->pidfd < 0)
+ return -errno;
+
+ c->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
if (missing & (SD_BUS_CREDS_PPID |
SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
@@ -794,13 +862,13 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
_cleanup_fclose_ FILE *f = NULL;
const char *p;
- p = procfs_file_alloca(pid, "status");
+ p = procfs_file_alloca(pidref->pid, "status");
f = fopen(p, "re");
if (!f) {
if (errno == ENOENT)
return -ESRCH;
- else if (!ERRNO_IS_PRIVILEGE(errno))
+ if (!ERRNO_IS_PRIVILEGE(errno))
return -errno;
} else {
@@ -958,7 +1026,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
const char *p;
- p = procfs_file_alloca(pid, "attr/current");
+ p = procfs_file_alloca(pidref->pid, "attr/current");
r = read_one_line_file(p, &c->label);
if (r < 0) {
if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
@@ -968,7 +1036,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_COMM) {
- r = pid_get_comm(pid, &c->comm);
+ r = pid_get_comm(pidref->pid, &c->comm);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r))
return r;
@@ -977,7 +1045,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_EXE) {
- r = get_process_exe(pid, &c->exe);
+ r = get_process_exe(pidref->pid, &c->exe);
if (r == -ESRCH) {
/* Unfortunately we cannot really distinguish
* the case here where the process does not
@@ -998,7 +1066,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & SD_BUS_CREDS_CMDLINE) {
const char *p;
- p = procfs_file_alloca(pid, "cmdline");
+ p = procfs_file_alloca(pidref->pid, "cmdline");
r = read_full_virtual_file(p, &c->cmdline, &c->cmdline_size);
if (r == -ENOENT)
return -ESRCH;
@@ -1016,7 +1084,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
_cleanup_free_ char *p = NULL;
- if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
+ if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pidref->pid, tid) < 0)
return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm);
@@ -1032,7 +1100,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
if (!c->cgroup) {
- r = cg_pid_get_path(NULL, pid, &c->cgroup);
+ r = cg_pid_get_path(NULL, pidref->pid, &c->cgroup);
if (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r))
return r;
@@ -1050,7 +1118,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
- r = audit_session_from_pid(pid, &c->audit_session_id);
+ r = audit_session_from_pid(pidref->pid, &c->audit_session_id);
if (r == -ENODATA) {
/* ENODATA means: no audit session id assigned */
c->audit_session_id = AUDIT_SESSION_INVALID;
@@ -1063,7 +1131,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
- r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
+ r = audit_loginuid_from_pid(pidref->pid, &c->audit_login_uid);
if (r == -ENODATA) {
/* ENODATA means: no audit login uid assigned */
c->audit_login_uid = UID_INVALID;
@@ -1076,7 +1144,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
}
if (missing & SD_BUS_CREDS_TTY) {
- r = get_ctty(pid, NULL, &c->tty);
+ r = get_ctty(pidref->pid, NULL, &c->tty);
if (r == -ENXIO) {
/* ENXIO means: process has no controlling TTY */
c->tty = NULL;
@@ -1088,16 +1156,12 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
c->mask |= SD_BUS_CREDS_TTY;
}
- /* In case only the exe path was to be read we cannot distinguish the case where the exe path was
- * unreadable because the process was a kernel thread, or when the process didn't exist at
- * all. Hence, let's do a final check, to be sure. */
- r = pid_is_alive(pid);
+ r = pidref_verify(pidref);
if (r < 0)
return r;
- if (r == 0)
- return -ESRCH;
- if (tid > 0 && tid != pid && pid_is_unwaited(tid) == 0)
+ /* Validate tid is still valid, too */
+ if (tid > 0 && tid != pidref->pid && pid_is_unwaited(tid) == 0)
return -ESRCH;
c->augmented = missing & c->mask;
@@ -1131,6 +1195,13 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
n->mask |= SD_BUS_CREDS_PID;
}
+ if (c->mask & mask & SD_BUS_CREDS_PIDFD) {
+ n->pidfd = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+ if (n->pidfd < 0)
+ return -errno;
+ n->mask |= SD_BUS_CREDS_PIDFD;
+ }
+
if (c->mask & mask & SD_BUS_CREDS_TID) {
n->tid = c->tid;
n->mask |= SD_BUS_CREDS_TID;
diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h
index 7806d9e..f45de1c 100644
--- a/src/libsystemd/sd-bus/bus-creds.h
+++ b/src/libsystemd/sd-bus/bus-creds.h
@@ -5,6 +5,9 @@
#include "sd-bus.h"
+#include "pidref.h"
+#include "user-util.h"
+
struct sd_bus_creds {
bool allocated;
unsigned n_ref;
@@ -27,6 +30,7 @@ struct sd_bus_creds {
pid_t ppid;
pid_t pid;
pid_t tid;
+ int pidfd;
char *comm;
char *tid_comm;
@@ -63,10 +67,22 @@ struct sd_bus_creds {
char *description, *unescaped_description;
};
+#define SD_BUS_CREDS_INIT_FIELDS \
+ .uid = UID_INVALID, \
+ .euid = UID_INVALID, \
+ .suid = UID_INVALID, \
+ .fsuid = UID_INVALID, \
+ .gid = GID_INVALID, \
+ .egid = GID_INVALID, \
+ .sgid = GID_INVALID, \
+ .fsgid = GID_INVALID, \
+ .pidfd = -EBADF, \
+ .audit_login_uid = UID_INVALID
+
sd_bus_creds* bus_creds_new(void);
void bus_creds_done(sd_bus_creds *c);
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid);
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid);
int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c
index 6d24f3b..aa46fec 100644
--- a/src/libsystemd/sd-bus/bus-dump.c
+++ b/src/libsystemd/sd-bus/bus-dump.c
@@ -355,6 +355,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
if (c->mask & SD_BUS_CREDS_PID)
fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
+ if (c->mask & SD_BUS_CREDS_PIDFD)
+ fprintf(f, "%sPIDFD=%syes%s", prefix, color, suffix);
if (c->mask & SD_BUS_CREDS_TID)
fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
if (c->mask & SD_BUS_CREDS_PPID) {
diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h
index 098a518..e0f4746 100644
--- a/src/libsystemd/sd-bus/bus-internal.h
+++ b/src/libsystemd/sd-bus/bus-internal.h
@@ -254,6 +254,9 @@ struct sd_bus {
char *address;
unsigned address_index;
+ uid_t connect_as_uid;
+ gid_t connect_as_gid;
+
int last_connect_error;
enum bus_auth auth;
@@ -269,6 +272,7 @@ struct sd_bus {
size_t n_groups;
union sockaddr_union sockaddr_peer;
socklen_t sockaddr_size_peer;
+ int pidfd;
uint64_t creds_mask;
diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c
index ab8b068..296f450 100644
--- a/src/libsystemd/sd-bus/bus-message.c
+++ b/src/libsystemd/sd-bus/bus-message.c
@@ -373,6 +373,7 @@ static int message_from_header(
if (!m)
return -ENOMEM;
+ m->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
m->sealed = true;
m->header = buffer;
@@ -469,6 +470,7 @@ _public_ int sd_bus_message_new(
return -ENOMEM;
t->n_ref = 1;
+ t->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
t->bus = sd_bus_ref(bus);
t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
t->header->endian = BUS_NATIVE_ENDIAN;
@@ -627,7 +629,7 @@ static int message_new_reply(
return r;
}
- t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
+ t->dont_send = FLAGS_SET(call->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED);
t->enforced_reply_signature = call->enforced_reply_signature;
/* let's copy the sensitive flag over. Let's do that as a safety precaution to keep a transaction
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index c25c40f..e528987 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -1701,7 +1701,7 @@ static bool names_are_valid(const char *signature, const char **names, names_fla
if ((*flags & NAMES_FIRST_PART || *flags & NAMES_SINGLE_PART) && **names != '\0')
*flags |= NAMES_PRESENT;
- for (;*flags & NAMES_PRESENT;) {
+ while (*flags & NAMES_PRESENT) {
size_t l;
if (!*signature)
diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c
index 5ade8e9..07179e0 100644
--- a/src/libsystemd/sd-bus/bus-socket.c
+++ b/src/libsystemd/sd-bus/bus-socket.c
@@ -217,7 +217,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
/* And possibly check the third line, too */
if (b->accept_fd) {
l = lines[i++];
- b->can_fds = !!memory_startswith(l, lines[i] - l, "AGREE_UNIX_FD");
+ b->can_fds = memory_startswith(l, lines[i] - l, "AGREE_UNIX_FD");
}
assert(i == n);
@@ -266,7 +266,7 @@ static int verify_anonymous_token(sd_bus *b, const char *p, size_t l) {
if (l % 2 != 0)
return 0;
- r = unhexmem(p, l, (void **) &token, &len);
+ r = unhexmem_full(p, l, /* secure = */ false, (void**) &token, &len);
if (r < 0)
return 0;
@@ -298,7 +298,7 @@ static int verify_external_token(sd_bus *b, const char *p, size_t l) {
if (l % 2 != 0)
return 0;
- r = unhexmem(p, l, (void**) &token, &len);
+ r = unhexmem_full(p, l, /* secure = */ false, (void**) &token, &len);
if (r < 0)
return 0;
@@ -503,11 +503,38 @@ static int bus_socket_write_auth(sd_bus *b) {
if (b->prefer_writev)
k = writev(b->output_fd, b->auth_iovec + b->auth_index, ELEMENTSOF(b->auth_iovec) - b->auth_index);
else {
+ CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct ucred))) control = {};
+
struct msghdr mh = {
.msg_iov = b->auth_iovec + b->auth_index,
.msg_iovlen = ELEMENTSOF(b->auth_iovec) - b->auth_index,
};
+ if (uid_is_valid(b->connect_as_uid) || gid_is_valid(b->connect_as_gid)) {
+
+ /* If we shall connect under some specific UID/GID, then synthesize an
+ * SCM_CREDENTIALS record accordingly. After all we want to adopt this UID/GID both
+ * for SO_PEERCRED (where we have to fork()) and SCM_CREDENTIALS (where we can just
+ * fake it via sendmsg()) */
+
+ struct ucred ucred = {
+ .pid = getpid_cached(),
+ .uid = uid_is_valid(b->connect_as_uid) ? b->connect_as_uid : getuid(),
+ .gid = gid_is_valid(b->connect_as_gid) ? b->connect_as_gid : getgid(),
+ };
+
+ mh.msg_control = &control;
+ mh.msg_controllen = sizeof(control);
+ struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
+ *cmsg = (struct cmsghdr) {
+ .cmsg_level = SOL_SOCKET,
+ .cmsg_type = SCM_CREDENTIALS,
+ .cmsg_len = CMSG_LEN(sizeof(struct ucred)),
+ };
+
+ memcpy(CMSG_DATA(cmsg), &ucred, sizeof(struct ucred));
+ }
+
k = sendmsg(b->output_fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
if (k < 0 && errno == ENOTSOCK) {
b->prefer_writev = true;
@@ -643,14 +670,20 @@ static void bus_get_peercred(sd_bus *b) {
/* Get the SELinux context of the peer */
r = getpeersec(b->input_fd, &b->label);
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
- log_debug_errno(r, "Failed to determine peer security context: %m");
+ log_debug_errno(r, "Failed to determine peer security context, ignoring: %m");
/* Get the list of auxiliary groups of the peer */
r = getpeergroups(b->input_fd, &b->groups);
if (r >= 0)
b->n_groups = (size_t) r;
else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
- log_debug_errno(r, "Failed to determine peer's group list: %m");
+ log_debug_errno(r, "Failed to determine peer's group list, ignoring: %m");
+
+ r = getpeerpidfd(b->input_fd);
+ if (r < 0)
+ log_debug_errno(r, "Failed to determine peer pidfd, ignoring: %m");
+ else
+ close_and_replace(b->pidfd, r);
/* Let's query the peers socket address, it might carry information such as the peer's comm or
* description string */
@@ -943,6 +976,66 @@ static int bind_description(sd_bus *b, int fd, int family) {
return 0;
}
+static int connect_as(int fd, const struct sockaddr *sa, socklen_t salen, uid_t uid, gid_t gid) {
+ _cleanup_(close_pairp) int pfd[2] = EBADF_PAIR;
+ ssize_t n;
+ int r;
+
+ /* Shortcut if we are not supposed to drop privileges */
+ if (!uid_is_valid(uid) && !gid_is_valid(gid))
+ return RET_NERRNO(connect(fd, sa, salen));
+
+ /* This changes identity to the specified uid/gid and issues connect() as that. This is useful to
+ * make sure SO_PEERCRED reports the selected UID/GID rather than the usual one of the caller. */
+
+ if (pipe2(pfd, O_CLOEXEC) < 0)
+ return -errno;
+
+ r = safe_fork("(sd-setresuid)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_WAIT, /* ret_pid= */ NULL);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* child */
+
+ pfd[0] = safe_close(pfd[0]);
+
+ r = RET_NERRNO(setgroups(0, NULL));
+ if (r < 0)
+ goto child_finish;
+
+ if (gid_is_valid(gid)) {
+ r = RET_NERRNO(setresgid(gid, gid, gid));
+ if (r < 0)
+ goto child_finish;
+ }
+
+ if (uid_is_valid(uid)) {
+ r = RET_NERRNO(setresuid(uid, uid, uid));
+ if (r < 0)
+ goto child_finish;
+ }
+
+ r = RET_NERRNO(connect(fd, sa, salen));
+ if (r < 0)
+ goto child_finish;
+
+ r = 0;
+
+ child_finish:
+ n = write(pfd[1], &r, sizeof(r));
+ if (n != sizeof(r))
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ n = read(pfd[0], &r, sizeof(r));
+ if (n != sizeof(r))
+ return -EIO;
+
+ return r;
+}
+
int bus_socket_connect(sd_bus *b) {
bool inotify_done = false;
int r;
@@ -974,8 +1067,9 @@ int bus_socket_connect(sd_bus *b) {
b->output_fd = b->input_fd;
bus_socket_setup(b);
- if (connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size) < 0) {
- if (errno == EINPROGRESS) {
+ r = connect_as(b->input_fd, &b->sockaddr.sa, b->sockaddr_size, b->connect_as_uid, b->connect_as_gid);
+ if (r < 0) {
+ if (r == -EINPROGRESS) {
/* If we have any inotify watches open, close them now, we don't need them anymore, as
* we have successfully initiated a connection */
@@ -988,7 +1082,7 @@ int bus_socket_connect(sd_bus *b) {
return 1;
}
- if (IN_SET(errno, ENOENT, ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */
+ if (IN_SET(r, -ENOENT, -ECONNREFUSED) && /* ENOENT → unix socket doesn't exist at all; ECONNREFUSED → unix socket stale */
b->watch_bind &&
b->sockaddr.sa.sa_family == AF_UNIX &&
b->sockaddr.un.sun_path[0] != 0) {
@@ -1016,7 +1110,7 @@ int bus_socket_connect(sd_bus *b) {
inotify_done = true;
} else
- return -errno;
+ return r;
} else
break;
}
diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c
index f9c59a1..6f6fa2d 100644
--- a/src/libsystemd/sd-bus/bus-track.c
+++ b/src/libsystemd/sd-bus/bus-track.c
@@ -69,7 +69,7 @@ static void bus_track_add_to_queue(sd_bus_track *track) {
return;
/* still referenced? */
- if (hashmap_size(track->names) > 0)
+ if (!hashmap_isempty(track->names))
return;
/* Nothing to call? */
diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c
index 8befc97..1a642cb 100644
--- a/src/libsystemd/sd-bus/sd-bus.c
+++ b/src/libsystemd/sd-bus/sd-bus.c
@@ -30,6 +30,7 @@
#include "constants.h"
#include "errno-util.h"
#include "fd-util.h"
+#include "format-util.h"
#include "glyph-util.h"
#include "hexdecoct.h"
#include "hostname-util.h"
@@ -151,6 +152,14 @@ void bus_close_inotify_fd(sd_bus *b) {
b->n_inotify_watches = 0;
}
+static void bus_close_fds(sd_bus *b) {
+ assert(b);
+
+ bus_close_io_fds(b);
+ bus_close_inotify_fd(b);
+ b->pidfd = safe_close(b->pidfd);
+}
+
static void bus_reset_queues(sd_bus *b) {
assert(b);
@@ -191,8 +200,7 @@ static sd_bus* bus_free(sd_bus *b) {
if (b->default_bus_ptr)
*b->default_bus_ptr = NULL;
- bus_close_io_fds(b);
- bus_close_inotify_fd(b);
+ bus_close_fds(b);
free(b->label);
free(b->groups);
@@ -256,7 +264,10 @@ _public_ int sd_bus_new(sd_bus **ret) {
.n_groups = SIZE_MAX,
.close_on_exit = true,
.ucred = UCRED_INVALID,
+ .pidfd = -EBADF,
.runtime_scope = _RUNTIME_SCOPE_INVALID,
+ .connect_as_uid = UID_INVALID,
+ .connect_as_gid = GID_INVALID,
};
/* We guarantee that wqueue always has space for at least one entry */
@@ -321,7 +332,7 @@ _public_ int sd_bus_set_bus_client(sd_bus *bus, int b) {
assert_return(!bus->patch_sender, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->bus_client = !!b;
+ bus->bus_client = b;
return 0;
}
@@ -331,7 +342,7 @@ _public_ int sd_bus_set_monitor(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->is_monitor = !!b;
+ bus->is_monitor = b;
return 0;
}
@@ -341,7 +352,7 @@ _public_ int sd_bus_negotiate_fds(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->accept_fd = !!b;
+ bus->accept_fd = b;
return 0;
}
@@ -353,7 +364,7 @@ _public_ int sd_bus_negotiate_timestamp(sd_bus *bus, int b) {
/* This is not actually supported by any of our transports these days, but we do honour it for synthetic
* replies, and maybe one day classic D-Bus learns this too */
- bus->attach_timestamp = !!b;
+ bus->attach_timestamp = b;
return 0;
}
@@ -380,7 +391,7 @@ _public_ int sd_bus_set_server(sd_bus *bus, int b, sd_id128_t server_id) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->is_server = !!b;
+ bus->is_server = b;
bus->server_id = server_id;
return 0;
}
@@ -391,7 +402,7 @@ _public_ int sd_bus_set_anonymous(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->anonymous_auth = !!b;
+ bus->anonymous_auth = b;
return 0;
}
@@ -401,7 +412,7 @@ _public_ int sd_bus_set_trusted(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->trusted = !!b;
+ bus->trusted = b;
return 0;
}
@@ -419,7 +430,7 @@ _public_ int sd_bus_set_allow_interactive_authorization(sd_bus *bus, int b) {
assert_return(bus = bus_resolve(bus), -ENOPKG);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->allow_interactive_authorization = !!b;
+ bus->allow_interactive_authorization = b;
return 0;
}
@@ -437,7 +448,7 @@ _public_ int sd_bus_set_watch_bind(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->watch_bind = !!b;
+ bus->watch_bind = b;
return 0;
}
@@ -455,7 +466,7 @@ _public_ int sd_bus_set_connected_signal(sd_bus *bus, int b) {
assert_return(bus->state == BUS_UNSET, -EPERM);
assert_return(!bus_origin_changed(bus), -ECHILD);
- bus->connected_signal = !!b;
+ bus->connected_signal = b;
return 0;
}
@@ -640,7 +651,7 @@ int bus_start_running(sd_bus *bus) {
static int parse_address_key(const char **p, const char *key, char **value) {
_cleanup_free_ char *r = NULL;
- size_t l, n = 0;
+ size_t n = 0;
const char *a;
assert(p);
@@ -648,17 +659,14 @@ static int parse_address_key(const char **p, const char *key, char **value) {
assert(value);
if (key) {
- l = strlen(key);
- if (strncmp(*p, key, l) != 0)
- return 0;
-
- if ((*p)[l] != '=')
+ a = startswith(*p, key);
+ if (!a || *a != '=')
return 0;
if (*value)
return -EINVAL;
- a = *p + l + 1;
+ a++;
} else
a = *p;
@@ -717,7 +725,7 @@ static void skip_address_key(const char **p) {
}
static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
- _cleanup_free_ char *path = NULL, *abstract = NULL;
+ _cleanup_free_ char *path = NULL, *abstract = NULL, *uids = NULL, *gids = NULL;
size_t l;
int r;
@@ -745,6 +753,18 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
else if (r > 0)
continue;
+ r = parse_address_key(p, "uid", &uids);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
+ r = parse_address_key(p, "gid", &gids);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ continue;
+
skip_address_key(p);
}
@@ -781,6 +801,17 @@ static int parse_unix_address(sd_bus *b, const char **p, char **guid) {
b->sockaddr_size = offsetof(struct sockaddr_un, sun_path) + 1 + l;
}
+ if (uids) {
+ r = parse_uid(uids, &b->connect_as_uid);
+ if (r < 0)
+ return r;
+ }
+ if (gids) {
+ r = parse_gid(gids, &b->connect_as_gid);
+ if (r < 0)
+ return r;
+ }
+
b->is_local = true;
return 0;
@@ -1102,8 +1133,7 @@ static int bus_start_address(sd_bus *b) {
assert(b);
for (;;) {
- bus_close_io_fds(b);
- bus_close_inotify_fd(b);
+ bus_close_fds(b);
bus_kill_exec(b);
@@ -1486,9 +1516,15 @@ interpret_port_as_machine_old_syntax:
return -ENOMEM;
}
- a = strjoin("unixexec:path=ssh,argv1=-xT", p ? ",argv2=-p,argv3=" : "", strempty(p),
- ",argv", p ? "4" : "2", "=--,argv", p ? "5" : "3", "=", e,
- ",argv", p ? "6" : "4", "=systemd-stdio-bridge", c);
+ const char *ssh = secure_getenv("SYSTEMD_SSH") ?: "ssh";
+ _cleanup_free_ char *ssh_escaped = bus_address_escape(ssh);
+ if (!ssh_escaped)
+ return -ENOMEM;
+
+ a = strjoin("unixexec:path=", ssh_escaped, ",argv1=-xT",
+ p ? ",argv2=-p,argv3=" : "", strempty(p),
+ ",argv", p ? "4" : "2", "=--,argv", p ? "5" : "3", "=", e,
+ ",argv", p ? "6" : "4", "=systemd-stdio-bridge", c);
if (!a)
return -ENOMEM;
@@ -1668,10 +1704,7 @@ static int user_and_machine_equivalent(const char *user_and_machine) {
return true;
/* Otherwise, we have to figure out our user id and name, and compare things with that. */
- char buf[DECIMAL_STR_MAX(uid_t)];
- xsprintf(buf, UID_FMT, uid);
-
- f = startswith(user_and_machine, buf);
+ f = startswith(user_and_machine, FORMAT_UID(uid));
if (!f) {
un = getusername_malloc();
if (!un)
@@ -1775,8 +1808,7 @@ _public_ void sd_bus_close(sd_bus *bus) {
* the bus object and the bus may be freed */
bus_reset_queues(bus);
- bus_close_io_fds(bus);
- bus_close_inotify_fd(bus);
+ bus_close_fds(bus);
}
_public_ sd_bus *sd_bus_close_unref(sd_bus *bus) {
@@ -4123,13 +4155,13 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
for (template_pos = path_template; *template_pos; ) {
const char *sep;
- size_t length;
+ size_t length, path_length;
char *label;
/* verify everything until the next '%' matches verbatim */
sep = strchrnul(template_pos, '%');
length = sep - template_pos;
- if (strncmp(path_pos, template_pos, length))
+ if (!strneq(path_pos, template_pos, length))
return 0;
path_pos += length;
@@ -4150,8 +4182,8 @@ _public_ int sd_bus_path_decode_many(const char *path, const char *path_template
/* verify the suffixes match */
sep = strchrnul(path_pos, '/');
- if (sep - path_pos < (ssize_t)length ||
- strncmp(sep - length, template_pos, length))
+ path_length = sep - path_pos;
+ if (length > path_length || !strneq(sep - length, template_pos, length))
return 0;
template_pos += length; /* skip over matched label */
diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c
index da1340f..d06853b 100644
--- a/src/libsystemd/sd-bus/test-bus-chat.c
+++ b/src/libsystemd/sd-bus/test-bus-chat.c
@@ -432,8 +432,7 @@ static void* client2(void *p) {
if (r < 0)
log_debug("Failed to issue method call: %s", bus_error_message(&error, r));
else {
- log_error("Slow call unexpectedly succeed.");
- r = -ENOANO;
+ r = log_error_errno(SYNTHETIC_ERRNO(ENOANO), "Slow call unexpectedly succeeded.");
goto finish;
}
diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c
index 3e14627..b569986 100644
--- a/src/libsystemd/sd-bus/test-bus-cleanup.c
+++ b/src/libsystemd/sd-bus/test-bus-cleanup.c
@@ -30,7 +30,7 @@ static void test_bus_fork(void) {
r = safe_fork("(bus-fork-test)", FORK_WAIT|FORK_LOG, NULL);
if (r == 0) {
assert_se(bus);
- assert_se(sd_bus_is_ready(bus) == -ECHILD);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_is_ready(bus) == -ECHILD);
assert_se(sd_bus_flush_close_unref(bus) == NULL);
assert_se(sd_bus_close_unref(bus) == NULL);
assert_se(sd_bus_unref(bus) == NULL);
diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c
index 13801be..7eb7a38 100644
--- a/src/libsystemd/sd-bus/test-bus-creds.c
+++ b/src/libsystemd/sd-bus/test-bus-creds.c
@@ -4,6 +4,7 @@
#include "bus-dump.h"
#include "cgroup-util.h"
+#include "errno-util.h"
#include "tests.h"
int main(int argc, char *argv[]) {
@@ -12,7 +13,7 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
- if (cg_unified() == -ENOMEDIUM)
+ if (IN_SET(cg_unified(), -ENOMEDIUM, -ENOENT))
return log_tests_skipped("/sys/fs/cgroup/ not available");
r = sd_bus_creds_new_from_pid(&creds, 0, _SD_BUS_CREDS_ALL);
@@ -24,11 +25,30 @@ int main(int argc, char *argv[]) {
creds = sd_bus_creds_unref(creds);
r = sd_bus_creds_new_from_pid(&creds, 1, _SD_BUS_CREDS_ALL);
- if (r != -EACCES) {
+ if (!ERRNO_IS_NEG_PRIVILEGE(r)) {
assert_se(r >= 0);
putchar('\n');
bus_creds_dump(creds, NULL, true);
}
+ creds = sd_bus_creds_unref(creds);
+
+ _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+ r = sd_bus_default_system(&bus);
+ if (r < 0)
+ log_warning_errno(r, "Unable to connect to system bus, skipping rest of test.");
+ else {
+ const char *unique;
+
+ assert_se(sd_bus_get_unique_name(bus, &unique) >= 0);
+
+ r = sd_bus_get_name_creds(bus, unique, _SD_BUS_CREDS_ALL, &creds);
+ log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_get_name_creds: %m");
+ assert_se(r >= 0);
+
+ putchar('\n');
+ bus_creds_dump(creds, NULL, true);
+ }
+
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c
index a55f3f9..91045c0 100644
--- a/src/libsystemd/sd-bus/test-bus-error.c
+++ b/src/libsystemd/sd-bus/test-bus-error.c
@@ -213,8 +213,8 @@ TEST(errno_mapping_custom) {
assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT);
- assert_se(sd_bus_error_add_map(test_errors_bad1) == -EINVAL);
- assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_error_add_map(test_errors_bad1) == -EINVAL);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_error_add_map(test_errors_bad2) == -EINVAL);
}
TEST(sd_bus_error_set_errnof) {
diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c
index 0044d33..92da627 100644
--- a/src/libsystemd/sd-bus/test-bus-marshal.c
+++ b/src/libsystemd/sd-bus/test-bus-marshal.c
@@ -42,8 +42,8 @@ static void test_bus_path_encode(void) {
assert_se(sd_bus_path_decode(a, "/waldo", &b) == 0 && b == NULL);
assert_se(sd_bus_path_decode(a, "/foo/bar", &b) > 0 && streq(b, "waldo"));
- assert_se(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
- assert_se(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_path_encode("xxxx", "waldo", &c) < 0);
+ ASSERT_RETURN_EXPECTED_SE(sd_bus_path_encode("/foo/", "waldo", &c) < 0);
assert_se(sd_bus_path_encode("/foo/bar", "", &c) >= 0 && streq(c, "/foo/bar/_"));
assert_se(sd_bus_path_decode(c, "/foo/bar", &d) > 0 && streq(d, ""));
diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c
index ccdd0d5..2847ba8 100644
--- a/src/libsystemd/sd-bus/test-bus-objects.c
+++ b/src/libsystemd/sd-bus/test-bus-objects.c
@@ -494,10 +494,9 @@ static int client(struct context *c) {
}
assert_se(sd_bus_message_exit_container(reply) >= 0);
- if (streq(path, "/value/a")) {
+ if (streq(path, "/value/a"))
/* ObjectManager must be here */
assert_se(found_object_manager_interface);
- }
} else
assert_se(sd_bus_message_skip(reply, "a{sa{sv}}") >= 0);
diff --git a/src/libsystemd/sd-bus/test-bus-peersockaddr.c b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
index 79556e8..a7bba17 100644
--- a/src/libsystemd/sd-bus/test-bus-peersockaddr.c
+++ b/src/libsystemd/sd-bus/test-bus-peersockaddr.c
@@ -5,10 +5,39 @@
#include "sd-bus.h"
+#include "bus-dump.h"
+#include "bus-util.h"
#include "fd-util.h"
#include "process-util.h"
#include "socket-util.h"
+#include "sort-util.h"
#include "tests.h"
+#include "user-util.h"
+
+static bool gid_list_contained(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ assert_se(a || n == 0);
+ assert_se(b || m == 0);
+
+ /* Checks if every entry in a[] is also in b[] */
+
+ for (size_t i = 0; i < n; i++) {
+ size_t j;
+
+ for (j = 0; j < m; j++)
+ if (a[i] == b[j])
+ break;
+
+ if (j >= m)
+ return false;
+ }
+
+ return true;
+}
+
+static bool gid_list_same(const gid_t *a, size_t n, const gid_t *b, size_t m) {
+ return gid_list_contained(a, n, b, m) &&
+ gid_list_contained(b, m, a, n);
+}
static void *server(void *p) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -27,11 +56,13 @@ static void *server(void *p) {
assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
TAKE_FD(fd);
assert_se(sd_bus_set_server(bus, true, id) >= 0);
- assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION) >= 0);
+ assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS) >= 0);
assert_se(sd_bus_start(bus) >= 0);
- assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION, &c) >= 0);
+ assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD|SD_BUS_CREDS_SUPPLEMENTARY_GIDS, &c) >= 0);
+
+ bus_creds_dump(c, /* f= */ NULL, /* terse= */ false);
uid_t u;
assert_se(sd_bus_creds_get_euid(c, &u) >= 0);
@@ -45,6 +76,26 @@ static void *server(void *p) {
assert_se(sd_bus_creds_get_pid(c, &pid) >= 0);
assert_se(pid == getpid_cached());
+ int pidfd = -EBADF;
+ if (sd_bus_creds_get_pidfd_dup(c, &pidfd) >= 0) {
+ _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+
+ assert_se(pidref_set_pidfd_take(&pidref, pidfd) >= 0);
+ assert_se(pidref.pid == getpid_cached());
+ }
+
+ const gid_t *gl = NULL;
+ int n;
+ n = sd_bus_creds_get_supplementary_gids(c, &gl);
+
+ if (n >= 0) {
+ _cleanup_free_ gid_t *gg = NULL;
+ r = getgroups_alloc(&gg);
+ assert_se(r >= 0);
+
+ assert_se(gid_list_same(gl, n, gg, r));
+ }
+
const char *comm;
assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
assert_se(pid_get_comm(0, &our_comm) >= 0);
diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c
index 6a60cde..4945d82 100644
--- a/src/libsystemd/sd-daemon/sd-daemon.c
+++ b/src/libsystemd/sd-daemon/sd-daemon.c
@@ -76,7 +76,7 @@ _public_ int sd_listen_fds(int unset_environment) {
goto finish;
}
- for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
+ for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) {
r = fd_cloexec(fd, true);
if (r < 0)
goto finish;
@@ -456,6 +456,7 @@ static int pid_notify_with_fds_internal(
const char *state,
const int *fds,
unsigned n_fds) {
+
SocketAddress address;
struct iovec iovec;
struct msghdr msghdr = {
@@ -464,19 +465,12 @@ static int pid_notify_with_fds_internal(
.msg_name = &address.sockaddr,
};
_cleanup_close_ int fd = -EBADF;
- struct cmsghdr *cmsg = NULL;
- const char *e;
- bool send_ucred;
- ssize_t n;
int type, r;
- if (!state)
- return -EINVAL;
-
- if (n_fds > 0 && !fds)
- return -EINVAL;
+ assert_return(state, -EINVAL);
+ assert_return(fds || n_fds == 0, -EINVAL);
- e = getenv("NOTIFY_SOCKET");
+ const char *e = getenv("NOTIFY_SOCKET");
if (!e)
return 0;
@@ -530,12 +524,14 @@ static int pid_notify_with_fds_internal(
iovec = IOVEC_MAKE_STRING(state);
- send_ucred =
+ bool send_ucred =
(pid != 0 && pid != getpid_cached()) ||
getuid() != geteuid() ||
getgid() != getegid();
if (n_fds > 0 || send_ucred) {
+ struct cmsghdr *cmsg;
+
/* CMSG_SPACE(0) may return value different than zero, which results in miscalculated controllen. */
msghdr.msg_controllen =
(n_fds > 0 ? CMSG_SPACE(sizeof(int) * n_fds) : 0) +
@@ -569,6 +565,8 @@ static int pid_notify_with_fds_internal(
}
}
+ ssize_t n;
+
do {
/* First try with fake ucred data, as requested */
n = sendmsg(fd, &msghdr, MSG_NOSIGNAL);
@@ -594,6 +592,19 @@ static int pid_notify_with_fds_internal(
}
} while (!iovec_increment(msghdr.msg_iov, msghdr.msg_iovlen, n));
+ if (address.sockaddr.sa.sa_family == AF_VSOCK && IN_SET(type, SOCK_STREAM, SOCK_SEQPACKET)) {
+ /* For AF_VSOCK, we need to close the socket to signal the end of the message. */
+ if (shutdown(fd, SHUT_WR) < 0)
+ return log_debug_errno(errno, "Failed to shutdown notify socket: %m");
+
+ char c;
+ n = recv(fd, &c, sizeof(c), MSG_NOSIGNAL);
+ if (n < 0)
+ return log_debug_errno(errno, "Failed to wait for EOF on notify socket: %m");
+ if (n > 0)
+ return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Unexpectedly received data on notify socket.");
+ }
+
return 1;
}
@@ -650,7 +661,7 @@ _public_ int sd_notify(int unset_environment, const char *state) {
_public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format, ...) {
_cleanup_free_ char *p = NULL;
- int r;
+ int r = 0, k;
if (format) {
va_list ap;
@@ -659,16 +670,20 @@ _public_ int sd_pid_notifyf(pid_t pid, int unset_environment, const char *format
r = vasprintf(&p, format, ap);
va_end(ap);
- if (r < 0 || !p)
- return -ENOMEM;
+ if (r < 0 || !p) {
+ r = -ENOMEM;
+ p = mfree(p); /* If vasprintf failed, do not use the string,
+ * even if something was returned. */
+ }
}
- return sd_pid_notify(pid, unset_environment, p);
+ k = sd_pid_notify(pid, unset_environment, p);
+ return r < 0 ? r : k;
}
_public_ int sd_notifyf(int unset_environment, const char *format, ...) {
_cleanup_free_ char *p = NULL;
- int r;
+ int r = 0, k;
if (format) {
va_list ap;
@@ -677,11 +692,15 @@ _public_ int sd_notifyf(int unset_environment, const char *format, ...) {
r = vasprintf(&p, format, ap);
va_end(ap);
- if (r < 0 || !p)
- return -ENOMEM;
+ if (r < 0 || !p) {
+ r = -ENOMEM;
+ p = mfree(p); /* If vasprintf failed, do not use the string,
+ * even if something was returned. */
+ }
}
- return sd_pid_notify(0, unset_environment, p);
+ k = sd_pid_notify(0, unset_environment, p);
+ return r < 0 ? r : k;
}
_public_ int sd_pid_notifyf_with_fds(
@@ -691,27 +710,31 @@ _public_ int sd_pid_notifyf_with_fds(
const char *format, ...) {
_cleanup_free_ char *p = NULL;
- int r;
+ int r = 0, k;
/* Paranoia check: we traditionally used 'unsigned' as array size, but we nowadays more correctly use
* 'size_t'. sd_pid_notifyf_with_fds() and sd_pid_notify_with_fds() are from different eras, hence
* differ in this. Let's catch resulting incompatibilites early, even though they are pretty much
* theoretic only */
if (n_fds > UINT_MAX)
- return -E2BIG;
+ r = -E2BIG;
- if (format) {
+ else if (format) {
va_list ap;
va_start(ap, format);
r = vasprintf(&p, format, ap);
va_end(ap);
- if (r < 0 || !p)
- return -ENOMEM;
+ if (r < 0 || !p) {
+ r = -ENOMEM;
+ p = mfree(p); /* If vasprintf failed, do not use the string,
+ * even if something was returned. */
+ }
}
- return sd_pid_notify_with_fds(pid, unset_environment, p, fds, n_fds);
+ k = sd_pid_notify_with_fds(pid, unset_environment, p, fds, n_fds);
+ return r < 0 ? r : k;
}
_public_ int sd_booted(void) {
diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c
index 15c5c42..71ab3d8 100644
--- a/src/libsystemd/sd-device/device-enumerator.c
+++ b/src/libsystemd/sd-device/device-enumerator.c
@@ -370,12 +370,8 @@ static int enumerator_sort_devices(sd_device_enumerator *enumerator) {
HASHMAP_FOREACH_KEY(device, syspath, enumerator->devices_by_syspath) {
_cleanup_free_ char *p = NULL;
- const char *subsys;
- if (sd_device_get_subsystem(device, &subsys) < 0)
- continue;
-
- if (!streq(subsys, *prioritized_subsystem))
+ if (!device_in_subsystem(device, *prioritized_subsystem))
continue;
devices[n++] = sd_device_ref(device);
@@ -662,10 +658,8 @@ static int enumerator_add_parent_devices(
continue;
r = device_enumerator_add_device(enumerator, device);
- if (r < 0)
+ if (r <= 0) /* r == 0 means the device already exists, then no need to go further up. */
return r;
- if (r == 0) /* Exists already? Then no need to go further up. */
- return 0;
}
}
diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c
index bb4f9bd..a7ef03a 100644
--- a/src/libsystemd/sd-device/device-monitor.c
+++ b/src/libsystemd/sd-device/device-monitor.c
@@ -47,7 +47,7 @@ struct sd_device_monitor {
union sockaddr_union snl_trusted_sender;
bool bound;
- UidRange *mapped_userns_uid_range;
+ UIDRange *mapped_userns_uid_range;
Hashmap *subsystem_filter;
Set *tag_filter;
@@ -402,8 +402,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device_monitor, sd_device_monitor, device_monitor_free);
static int check_subsystem_filter(sd_device_monitor *m, sd_device *device) {
- const char *s, *subsystem, *d, *devtype = NULL;
- int r;
+ const char *s, *d;
assert(m);
assert(device);
@@ -411,20 +410,14 @@ static int check_subsystem_filter(sd_device_monitor *m, sd_device *device) {
if (hashmap_isempty(m->subsystem_filter))
return true;
- r = sd_device_get_subsystem(device, &subsystem);
- if (r < 0)
- return r;
-
- r = sd_device_get_devtype(device, &devtype);
- if (r < 0 && r != -ENOENT)
- return r;
-
HASHMAP_FOREACH_KEY(d, s, m->subsystem_filter) {
- if (!streq(s, subsystem))
+ if (!device_in_subsystem(device, s))
continue;
- if (!d || streq_ptr(d, devtype))
- return true;
+ if (d && !device_is_devtype(device, d))
+ continue;
+
+ return true;
}
return false;
@@ -480,7 +473,7 @@ static bool check_sender_uid(sd_device_monitor *m, uid_t uid) {
return true;
if (!m->mapped_userns_uid_range) {
- r = uid_range_load_userns(&m->mapped_userns_uid_range, NULL);
+ r = uid_range_load_userns(/* path = */ NULL, UID_RANGE_USERNS_INSIDE, &m->mapped_userns_uid_range);
if (r < 0)
log_monitor_errno(m, r, "Failed to load UID ranges mapped to the current user namespace, ignoring: %m");
}
diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c
index 0edabfb..cd85ec9 100644
--- a/src/libsystemd/sd-device/device-private.c
+++ b/src/libsystemd/sd-device/device-private.c
@@ -768,55 +768,96 @@ static bool device_has_info(sd_device *device) {
return false;
}
+bool device_should_have_db(sd_device *device) {
+ assert(device);
+
+ if (device_has_info(device))
+ return true;
+
+ if (major(device->devnum) != 0)
+ return true;
+
+ if (device->ifindex != 0)
+ return true;
+
+ return false;
+}
+
void device_set_db_persist(sd_device *device) {
assert(device);
device->db_persist = true;
}
-int device_update_db(sd_device *device) {
+static int device_get_db_path(sd_device *device, char **ret) {
const char *id;
char *path;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_(unlink_and_freep) char *path_tmp = NULL;
- bool has_info;
int r;
assert(device);
-
- has_info = device_has_info(device);
+ assert(ret);
r = device_get_device_id(device, &id);
if (r < 0)
return r;
- path = strjoina("/run/udev/data/", id);
+ path = path_join("/run/udev/data/", id);
+ if (!path)
+ return -ENOMEM;
+
+ *ret = path;
+ return 0;
+}
+
+int device_has_db(sd_device *device) {
+ _cleanup_free_ char *path = NULL;
+ int r;
+
+ assert(device);
+
+ r = device_get_db_path(device, &path);
+ if (r < 0)
+ return r;
+
+ return access(path, F_OK) >= 0;
+}
+
+int device_update_db(sd_device *device) {
+ _cleanup_(unlink_and_freep) char *path = NULL, *path_tmp = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ int r;
+
+ assert(device);
/* do not store anything for otherwise empty devices */
- if (!has_info && major(device->devnum) == 0 && device->ifindex == 0) {
- if (unlink(path) < 0 && errno != ENOENT)
- return -errno;
+ if (!device_should_have_db(device))
+ return device_delete_db(device);
- return 0;
- }
+ r = device_get_db_path(device, &path);
+ if (r < 0)
+ return r;
/* write a database file */
r = mkdir_parents(path, 0755);
if (r < 0)
- return r;
+ return log_device_debug_errno(device, r,
+ "sd-device: Failed to create parent directories of '%s': %m",
+ path);
r = fopen_temporary(path, &f, &path_tmp);
if (r < 0)
- return r;
+ return log_device_debug_errno(device, r,
+ "sd-device: Failed to create temporary file for database file '%s': %m",
+ path);
/* set 'sticky' bit to indicate that we should not clean the database when we transition from initrd
* to the real root */
- if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0) {
- r = -errno;
- goto fail;
- }
+ if (fchmod(fileno(f), device->db_persist ? 01644 : 0644) < 0)
+ return log_device_debug_errno(device, errno,
+ "sd-device: Failed to chmod temporary database file '%s': %m",
+ path_tmp);
- if (has_info) {
+ if (device_has_info(device)) {
const char *property, *value, *ct;
if (major(device->devnum) > 0) {
@@ -846,45 +887,55 @@ int device_update_db(sd_device *device) {
r = fflush_and_check(f);
if (r < 0)
- goto fail;
+ return log_device_debug_errno(device, r,
+ "sd-device: Failed to flush temporary database file '%s': %m",
+ path_tmp);
- if (rename(path_tmp, path) < 0) {
- r = -errno;
- goto fail;
- }
+ if (rename(path_tmp, path) < 0)
+ return log_device_debug_errno(device, errno,
+ "sd-device: Failed to rename temporary database file '%s' to '%s': %m",
+ path_tmp, path);
- path_tmp = mfree(path_tmp);
+ log_device_debug(device, "sd-device: Created database file '%s' for '%s'.", path, device->devpath);
- log_device_debug(device, "sd-device: Created %s file '%s' for '%s'", has_info ? "db" : "empty",
- path, device->devpath);
+ path_tmp = mfree(path_tmp);
+ path = mfree(path);
return 0;
-
-fail:
- (void) unlink(path);
-
- return log_device_debug_errno(device, r, "sd-device: Failed to create %s file '%s' for '%s'", has_info ? "db" : "empty", path, device->devpath);
}
int device_delete_db(sd_device *device) {
- const char *id;
- char *path;
+ _cleanup_free_ char *path = NULL;
int r;
assert(device);
- r = device_get_device_id(device, &id);
+ r = device_get_db_path(device, &path);
if (r < 0)
return r;
- path = strjoina("/run/udev/data/", id);
-
if (unlink(path) < 0 && errno != ENOENT)
return -errno;
return 0;
}
+int device_read_db_internal(sd_device *device, bool force) {
+ _cleanup_free_ char *path = NULL;
+ int r;
+
+ assert(device);
+
+ if (device->db_loaded || (!force && device->sealed))
+ return 0;
+
+ r = device_get_db_path(device, &path);
+ if (r < 0)
+ return r;
+
+ return device_read_db_internal_filename(device, path);
+}
+
static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = {
[SD_DEVICE_ADD] = "add",
[SD_DEVICE_REMOVE] = "remove",
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
index e8a6d52..85e8609 100644
--- a/src/libsystemd/sd-device/device-private.h
+++ b/src/libsystemd/sd-device/device-private.h
@@ -24,6 +24,7 @@ int device_get_sysattr_unsigned_full(sd_device *device, const char *sysattr, uns
static inline int device_get_sysattr_unsigned(sd_device *device, const char *sysattr, unsigned *ret_value) {
return device_get_sysattr_unsigned_full(device, sysattr, 0, ret_value);
}
+int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value);
int device_get_sysattr_bool(sd_device *device, const char *sysattr);
int device_get_device_id(sd_device *device, const char **ret);
int device_get_devlink_priority(sd_device *device, int *ret);
@@ -61,6 +62,8 @@ int device_get_properties_strv(sd_device *device, char ***ret);
int device_clone_with_db(sd_device *device, sd_device **ret);
int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
+bool device_should_have_db(sd_device *device);
+int device_has_db(sd_device *device);
int device_update_db(sd_device *device);
int device_delete_db(sd_device *device);
int device_read_db_internal_filename(sd_device *device, const char *filename); /* For fuzzer */
diff --git a/src/libsystemd/sd-device/device-util.c b/src/libsystemd/sd-device/device-util.c
index 529eff2..123629c 100644
--- a/src/libsystemd/sd-device/device-util.c
+++ b/src/libsystemd/sd-device/device-util.c
@@ -9,7 +9,6 @@
int devname_from_devnum(mode_t mode, dev_t devnum, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- _cleanup_free_ char *s = NULL;
const char *devname;
int r;
@@ -26,15 +25,10 @@ int devname_from_devnum(mode_t mode, dev_t devnum, char **ret) {
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = TAKE_PTR(s);
- return 0;
+ return strdup_to(ret, devname);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret) {
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_close_ int fd = -EBADF;
int r;
@@ -47,19 +41,16 @@ int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret) {
if (fd < 0)
return fd;
- if (ret) {
+ if (ret_devname) {
const char *devname;
- char *s;
r = sd_device_get_devname(dev, &devname);
if (r < 0)
return r;
- s = strdup(devname);
- if (!s)
- return -ENOMEM;
-
- *ret = s;
+ r = strdup_to(ret_devname, devname);
+ if (r < 0)
+ return r;
}
return TAKE_FD(fd);
@@ -139,3 +130,21 @@ char** device_make_log_fields(sd_device *device) {
return TAKE_PTR(strv);
}
+
+bool device_in_subsystem(sd_device *device, const char *subsystem) {
+ const char *s = NULL;
+
+ assert(device);
+
+ (void) sd_device_get_subsystem(device, &s);
+ return streq_ptr(s, subsystem);
+}
+
+bool device_is_devtype(sd_device *device, const char *devtype) {
+ const char *s = NULL;
+
+ assert(device);
+
+ (void) sd_device_get_devtype(device, &s);
+ return streq_ptr(s, devtype);
+}
diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h
index bf86ddc..b17993d 100644
--- a/src/libsystemd/sd-device/device-util.h
+++ b/src/libsystemd/sd-device/device-util.h
@@ -10,6 +10,7 @@
#include "alloc-util.h"
#include "log.h"
#include "macro.h"
+#include "strv.h"
#define device_unref_and_replace(a, b) \
unref_and_replace_full(a, b, sd_device_ref, sd_device_unref)
@@ -99,6 +100,16 @@ static inline int devname_from_stat_rdev(const struct stat *st, char **ret) {
assert(st);
return devname_from_devnum(st->st_mode, st->st_rdev, ret);
}
-int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
+int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret_devname);
char** device_make_log_fields(sd_device *device);
+
+bool device_in_subsystem(sd_device *device, const char *subsystem);
+bool device_is_devtype(sd_device *device, const char *devtype);
+
+static inline bool device_property_can_set(const char *property) {
+ return property &&
+ !STR_IN_SET(property,
+ "ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "DEVTYPE", "DRIVER",
+ "IFINDEX", "MAJOR", "MINOR", "SEQNUM", "SUBSYSTEM", "TAGS");
+}
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index 01e66b4..d8d1518 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -214,7 +214,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) {
/* Only operate on sysfs, i.e. refuse going down into /sys/fs/cgroup/ or similar places where
* things are not arranged as kobjects in kernel, and hence don't necessarily have
* kobject/attribute structure. */
- r = getenv_bool_secure("SYSTEMD_DEVICE_VERIFY_SYSFS");
+ r = secure_getenv_bool("SYSTEMD_DEVICE_VERIFY_SYSFS");
if (r < 0 && r != -ENXIO)
log_debug_errno(r, "Failed to parse $SYSTEMD_DEVICE_VERIFY_SYSFS value: %m");
if (r != 0) {
@@ -283,7 +283,7 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) {
int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
_cleanup_free_ char *syspath = NULL;
- const char *t, *subsystem = NULL;
+ const char *t;
dev_t n;
int r;
@@ -314,10 +314,7 @@ int device_new_from_mode_and_devnum(sd_device **ret, mode_t mode, dev_t devnum)
if (n != devnum)
return -ENXIO;
- r = sd_device_get_subsystem(dev, &subsystem);
- if (r < 0 && r != -ENOENT)
- return r;
- if (streq_ptr(subsystem, "block") != !!S_ISBLK(mode))
+ if (device_in_subsystem(dev, "block") != !!S_ISBLK(mode))
return -ENXIO;
*ret = TAKE_PTR(dev);
@@ -348,17 +345,11 @@ _public_ int sd_device_new_from_ifname(sd_device **ret, const char *ifname) {
assert_return(ret, -EINVAL);
assert_return(ifname, -EINVAL);
- r = parse_ifindex(ifname);
- if (r > 0)
- return sd_device_new_from_ifindex(ret, r);
-
- if (ifname_valid(ifname)) {
- r = device_new_from_main_ifname(ret, ifname);
- if (r >= 0)
- return r;
- }
+ r = device_new_from_main_ifname(ret, ifname);
+ if (r >= 0)
+ return r;
- r = rtnl_resolve_link_alternative_name(NULL, ifname, &main_name);
+ r = rtnl_resolve_ifname_full(NULL, RESOLVE_IFNAME_ALTERNATIVE | RESOLVE_IFNAME_NUMERIC, ifname, &main_name, NULL);
if (r < 0)
return r;
@@ -367,14 +358,15 @@ _public_ int sd_device_new_from_ifname(sd_device **ret, const char *ifname) {
_public_ int sd_device_new_from_ifindex(sd_device **ret, int ifindex) {
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
- char ifname[IF_NAMESIZE];
+ _cleanup_free_ char *ifname = NULL;
int r, i;
assert_return(ret, -EINVAL);
assert_return(ifindex > 0, -EINVAL);
- if (format_ifname(ifindex, ifname) < 0)
- return -ENODEV;
+ r = rtnl_get_ifname_full(NULL, ifindex, &ifname, NULL);
+ if (r < 0)
+ return r;
r = device_new_from_main_ifname(&dev, ifname);
if (r < 0)
@@ -1222,37 +1214,27 @@ _public_ int sd_device_get_devtype(sd_device *device, const char **devtype) {
return !!device->devtype;
}
-_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret) {
- sd_device *parent = NULL;
+_public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *device, const char *subsystem, const char *devtype, sd_device **ret) {
int r;
- assert_return(child, -EINVAL);
+ assert_return(device, -EINVAL);
assert_return(subsystem, -EINVAL);
- r = sd_device_get_parent(child, &parent);
- while (r >= 0) {
- const char *parent_subsystem = NULL;
+ for (;;) {
+ r = sd_device_get_parent(device, &device);
+ if (r < 0)
+ return r;
- (void) sd_device_get_subsystem(parent, &parent_subsystem);
- if (streq_ptr(parent_subsystem, subsystem)) {
- const char *parent_devtype = NULL;
+ if (!device_in_subsystem(device, subsystem))
+ continue;
- if (!devtype)
- break;
+ if (devtype && !device_is_devtype(device, devtype))
+ continue;
- (void) sd_device_get_devtype(parent, &parent_devtype);
- if (streq_ptr(parent_devtype, devtype))
- break;
- }
- r = sd_device_get_parent(parent, &parent);
+ if (ret)
+ *ret = device;
+ return 0;
}
-
- if (r < 0)
- return r;
-
- if (ret)
- *ret = parent;
- return 0;
}
_public_ int sd_device_get_devnum(sd_device *device, dev_t *devnum) {
@@ -1778,24 +1760,6 @@ int device_read_db_internal_filename(sd_device *device, const char *filename) {
return 0;
}
-int device_read_db_internal(sd_device *device, bool force) {
- const char *id, *path;
- int r;
-
- assert(device);
-
- if (device->db_loaded || (!force && device->sealed))
- return 0;
-
- r = device_get_device_id(device, &id);
- if (r < 0)
- return r;
-
- path = strjoina("/run/udev/data/", id);
-
- return device_read_db_internal_filename(device, path);
-}
-
_public_ int sd_device_get_is_initialized(sd_device *device) {
int r;
@@ -2454,6 +2418,25 @@ int device_get_sysattr_unsigned_full(sd_device *device, const char *sysattr, uns
return v > 0;
}
+int device_get_sysattr_u32(sd_device *device, const char *sysattr, uint32_t *ret_value) {
+ const char *value;
+ int r;
+
+ r = sd_device_get_sysattr_value(device, sysattr, &value);
+ if (r < 0)
+ return r;
+
+ uint32_t v;
+ r = safe_atou32(value, &v);
+ if (r < 0)
+ return log_device_debug_errno(device, r, "Failed to parse '%s' attribute: %m", sysattr);
+
+ if (ret_value)
+ *ret_value = v;
+ /* We return "true" if the value is positive. */
+ return v > 0;
+}
+
int device_get_sysattr_bool(sd_device *device, const char *sysattr) {
const char *value;
int r;
@@ -2506,7 +2489,7 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr,
/* drop trailing newlines */
while (len > 0 && strchr(NEWLINE, _value[len - 1]))
- len --;
+ len--;
/* value length is limited to 4k */
if (len > 4096)
@@ -2609,7 +2592,7 @@ _public_ int sd_device_trigger_with_uuid(
_public_ int sd_device_open(sd_device *device, int flags) {
_cleanup_close_ int fd = -EBADF, fd2 = -EBADF;
- const char *devname, *subsystem = NULL;
+ const char *devname;
uint64_t q, diskseq = 0;
struct stat st;
dev_t devnum;
@@ -2630,10 +2613,6 @@ _public_ int sd_device_open(sd_device *device, int flags) {
if (r < 0)
return r;
- r = sd_device_get_subsystem(device, &subsystem);
- if (r < 0 && r != -ENOENT)
- return r;
-
fd = open(devname, FLAGS_SET(flags, O_PATH) ? flags : O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
@@ -2644,7 +2623,7 @@ _public_ int sd_device_open(sd_device *device, int flags) {
if (st.st_rdev != devnum)
return -ENXIO;
- if (streq_ptr(subsystem, "block") ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode))
+ if (device_in_subsystem(device, "block") ? !S_ISBLK(st.st_mode) : !S_ISCHR(st.st_mode))
return -ENXIO;
/* If flags has O_PATH, then we cannot check diskseq. Let's return earlier. */
diff --git a/src/libsystemd/sd-device/test-device-util.c b/src/libsystemd/sd-device/test-device-util.c
index bc8ab66..f7c9deb 100644
--- a/src/libsystemd/sd-device/test-device-util.c
+++ b/src/libsystemd/sd-device/test-device-util.c
@@ -1,23 +1,91 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-util.h"
+#include "mountpoint-util.h"
#include "tests.h"
TEST(log_device_full) {
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
int r;
+ (void) sd_device_new_from_subsystem_sysname(&dev, "net", "lo");
+
for (int level = LOG_ERR; level <= LOG_DEBUG; level++) {
- log_device_full(NULL, level, "test level=%d: %m", level);
+ log_device_full(dev, level, "test level=%d: %m", level);
- r = log_device_full_errno(NULL, level, EUCLEAN, "test level=%d errno=EUCLEAN: %m", level);
+ r = log_device_full_errno(dev, level, EUCLEAN, "test level=%d errno=EUCLEAN: %m", level);
assert_se(r == -EUCLEAN);
- r = log_device_full_errno(NULL, level, 0, "test level=%d errno=0: %m", level);
+ r = log_device_full_errno(dev, level, 0, "test level=%d errno=0: %m", level);
assert_se(r == 0);
- r = log_device_full_errno(NULL, level, SYNTHETIC_ERRNO(ENODATA), "test level=%d errno=S(ENODATA): %m", level);
+ r = log_device_full_errno(dev, level, SYNTHETIC_ERRNO(ENODATA), "test level=%d errno=S(ENODATA).", level);
assert_se(r == -ENODATA);
}
}
-DEFINE_TEST_MAIN(LOG_INFO);
+TEST(device_in_subsystem) {
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+ int r;
+
+ r = sd_device_new_from_subsystem_sysname(&dev, "net", "lo");
+ if (r == -ENODEV)
+ return (void) log_tests_skipped("net/lo does not exist");
+ assert_se(r >= 0);
+
+ assert_se(device_in_subsystem(dev, "net"));
+ assert_se(!device_in_subsystem(dev, "disk"));
+ assert_se(!device_in_subsystem(dev, "subsystem"));
+ assert_se(!device_in_subsystem(dev, ""));
+ assert_se(!device_in_subsystem(dev, NULL));
+
+ dev = sd_device_unref(dev);
+
+ assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net") >= 0);
+ assert_se(!device_in_subsystem(dev, "net"));
+ assert_se(!device_in_subsystem(dev, "disk"));
+ assert_se(device_in_subsystem(dev, "subsystem"));
+ assert_se(!device_in_subsystem(dev, ""));
+ assert_se(!device_in_subsystem(dev, NULL));
+
+ dev = sd_device_unref(dev);
+
+ assert_se(sd_device_new_from_syspath(&dev, "/sys/class") >= 0);
+ assert_se(!device_in_subsystem(dev, "net"));
+ assert_se(!device_in_subsystem(dev, "disk"));
+ assert_se(!device_in_subsystem(dev, "subsystem"));
+ assert_se(!device_in_subsystem(dev, ""));
+ assert_se(device_in_subsystem(dev, NULL));
+}
+
+TEST(device_is_devtype) {
+ _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
+ _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+
+ assert_se(sd_device_enumerator_new(&e) >= 0);
+ assert_se(sd_device_enumerator_add_match_subsystem(e, "disk", true) >= 0);
+
+ FOREACH_DEVICE(e, d) {
+ const char *t;
+
+ assert_se(sd_device_get_devtype(d, &t) >= 0);
+ assert_se(device_is_devtype(d, t));
+ assert_se(!device_is_devtype(d, "hoge"));
+ assert_se(!device_is_devtype(d, ""));
+ assert_se(!device_is_devtype(d, NULL));
+ }
+
+ assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net") >= 0);
+ assert_se(!device_is_devtype(dev, "hoge"));
+ assert_se(!device_is_devtype(dev, ""));
+ assert_se(device_is_devtype(dev, NULL));
+}
+
+static int intro(void) {
+ if (path_is_mount_point("/sys") <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/libsystemd/sd-device/test-sd-device-monitor.c b/src/libsystemd/sd-device/test-sd-device-monitor.c
index e124e00..3dbf987 100644
--- a/src/libsystemd/sd-device/test-sd-device-monitor.c
+++ b/src/libsystemd/sd-device/test-sd-device-monitor.c
@@ -10,6 +10,7 @@
#include "device-private.h"
#include "device-util.h"
#include "macro.h"
+#include "mountpoint-util.h"
#include "path-util.h"
#include "stat-util.h"
#include "string-util.h"
@@ -298,6 +299,9 @@ int main(int argc, char *argv[]) {
if (getuid() != 0)
return log_tests_skipped("not root");
+ if (path_is_mount_point("/sys") <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
if (path_is_read_only_fs("/sys") > 0)
return log_tests_skipped("Running in container");
diff --git a/src/libsystemd/sd-device/test-sd-device-thread.c b/src/libsystemd/sd-device/test-sd-device-thread.c
index c99d179..539dabd 100644
--- a/src/libsystemd/sd-device/test-sd-device-thread.c
+++ b/src/libsystemd/sd-device/test-sd-device-thread.c
@@ -8,6 +8,7 @@
#include "sd-device.h"
#include "device-util.h"
+#include "tests.h"
#define handle_error_errno(error, msg) \
({ \
@@ -30,6 +31,8 @@ int main(int argc, char *argv[]) {
int r;
r = sd_device_new_from_syspath(&loopback, "/sys/class/net/lo");
+ if (r == -ENODEV)
+ return log_tests_skipped("Loopback device not found");
if (r < 0)
return handle_error_errno(r, "Failed to create loopback device object");
diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c
index bce99b5..9fde1a0 100644
--- a/src/libsystemd/sd-device/test-sd-device.c
+++ b/src/libsystemd/sd-device/test-sd-device.c
@@ -11,6 +11,7 @@
#include "errno-util.h"
#include "fd-util.h"
#include "hashmap.h"
+#include "mountpoint-util.h"
#include "nulstr-util.h"
#include "path-util.h"
#include "rm-rf.h"
@@ -675,4 +676,11 @@ TEST(devname_from_devnum) {
}
}
-DEFINE_TEST_MAIN(LOG_INFO);
+static int intro(void) {
+ if (path_is_mount_point("/sys") <= 0)
+ return log_tests_skipped("/sys is not mounted");
+
+ return EXIT_SUCCESS;
+}
+
+DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro);
diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h
index f4e38d7..d05bcf0 100644
--- a/src/libsystemd/sd-event/event-source.h
+++ b/src/libsystemd/sd-event/event-source.h
@@ -189,6 +189,9 @@ struct inode_data {
* iteration. */
int fd;
+ /* The path that the fd points to. The field is optional. */
+ char *path;
+
/* The inotify "watch descriptor" */
int wd;
diff --git a/src/libsystemd/sd-event/event-util.c b/src/libsystemd/sd-event/event-util.c
index a310122..862455e 100644
--- a/src/libsystemd/sd-event/event-util.c
+++ b/src/libsystemd/sd-event/event-util.c
@@ -151,3 +151,29 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle
return 0;
}
+
+int event_add_child_pidref(
+ sd_event *e,
+ sd_event_source **s,
+ const PidRef *pid,
+ int options,
+ sd_event_child_handler_t callback,
+ void *userdata) {
+
+ if (!pidref_is_set(pid))
+ return -ESRCH;
+
+ if (pid->fd >= 0)
+ return sd_event_add_child_pidfd(e, s, pid->fd, options, callback, userdata);
+
+ return sd_event_add_child(e, s, pid->pid, options, callback, userdata);
+}
+
+dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts) {
+ assert(e);
+ assert(ts);
+
+ assert_se(sd_event_now(e, CLOCK_REALTIME, &ts->realtime) >= 0);
+ assert_se(sd_event_now(e, CLOCK_MONOTONIC, &ts->monotonic) >= 0);
+ return ts;
+}
diff --git a/src/libsystemd/sd-event/event-util.h b/src/libsystemd/sd-event/event-util.h
index c185584..7002ca3 100644
--- a/src/libsystemd/sd-event/event-util.h
+++ b/src/libsystemd/sd-event/event-util.h
@@ -5,6 +5,8 @@
#include "sd-event.h"
+#include "pidref.h"
+
int event_reset_time(
sd_event *e,
sd_event_source **s,
@@ -32,3 +34,7 @@ static inline int event_source_disable(sd_event_source *s) {
}
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata);
+
+int event_add_child_pidref(sd_event *e, sd_event_source **s, const PidRef *pid, int options, sd_event_child_handler_t callback, void *userdata);
+
+dual_timestamp* event_dual_timestamp_now(sd_event *e, dual_timestamp *ts);
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index b6899df..a1305ef 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/epoll.h>
+#if HAVE_PIDFD_OPEN
+#include <sys/pidfd.h>
+#endif
#include <sys/timerfd.h>
#include <sys/wait.h>
@@ -1165,10 +1168,10 @@ static int source_set_pending(sd_event_source *s, bool b) {
assert(s->inotify.inode_data->inotify_data);
if (b)
- s->inotify.inode_data->inotify_data->n_pending ++;
+ s->inotify.inode_data->inotify_data->n_pending++;
else {
assert(s->inotify.inode_data->inotify_data->n_pending > 0);
- s->inotify.inode_data->inotify_data->n_pending --;
+ s->inotify.inode_data->inotify_data->n_pending--;
}
}
@@ -1574,7 +1577,7 @@ static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *us
static bool shall_use_pidfd(void) {
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
- return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
+ return secure_getenv_bool("SYSTEMD_PIDFD") != 0;
}
_public_ int sd_event_add_child(
@@ -1976,7 +1979,7 @@ _public_ int sd_event_add_memory_pressure(
env = secure_getenv("MEMORY_PRESSURE_WRITE");
if (env) {
- r = unbase64mem(env, SIZE_MAX, &write_buffer, &write_buffer_size);
+ r = unbase64mem(env, &write_buffer, &write_buffer_size);
if (r < 0)
return r;
}
@@ -2231,8 +2234,8 @@ static int inode_data_compare(const struct inode_data *x, const struct inode_dat
static void inode_data_hash_func(const struct inode_data *d, struct siphash *state) {
assert(d);
- siphash24_compress(&d->dev, sizeof(d->dev), state);
- siphash24_compress(&d->ino, sizeof(d->ino), state);
+ siphash24_compress_typesafe(d->dev, state);
+ siphash24_compress_typesafe(d->ino, state);
}
DEFINE_PRIVATE_HASH_OPS(inode_data_hash_ops, struct inode_data, inode_data_hash_func, inode_data_compare);
@@ -2272,6 +2275,7 @@ static void event_free_inode_data(
assert_se(hashmap_remove(d->inotify_data->inodes, d) == d);
}
+ free(d->path);
free(d);
}
@@ -2512,6 +2516,15 @@ static int event_add_inotify_fd_internal(
}
LIST_PREPEND(to_close, e->inode_data_to_close_list, inode_data);
+
+ _cleanup_free_ char *path = NULL;
+ r = fd_get_path(inode_data->fd, &path);
+ if (r < 0 && r != -ENOSYS) { /* The path is optional, hence ignore -ENOSYS. */
+ event_gc_inode_data(e, inode_data);
+ return r;
+ }
+
+ free_and_replace(inode_data->path, path);
}
/* Link our event source to the inode data object */
@@ -2797,6 +2810,13 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority)
}
LIST_PREPEND(to_close, s->event->inode_data_to_close_list, new_inode_data);
+
+ _cleanup_free_ char *path = NULL;
+ r = fd_get_path(new_inode_data->fd, &path);
+ if (r < 0 && r != -ENOSYS)
+ goto fail;
+
+ free_and_replace(new_inode_data->path, path);
}
/* Move the event source to the new inode data structure */
@@ -3281,13 +3301,29 @@ _public_ int sd_event_source_set_child_process_own(sd_event_source *s, int own)
return 0;
}
-_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *mask) {
+_public_ int sd_event_source_get_inotify_mask(sd_event_source *s, uint32_t *ret) {
assert_return(s, -EINVAL);
- assert_return(mask, -EINVAL);
+ assert_return(ret, -EINVAL);
assert_return(s->type == SOURCE_INOTIFY, -EDOM);
assert_return(!event_origin_changed(s->event), -ECHILD);
- *mask = s->inotify.mask;
+ *ret = s->inotify.mask;
+ return 0;
+}
+
+_public_ int sd_event_source_get_inotify_path(sd_event_source *s, const char **ret) {
+ assert_return(s, -EINVAL);
+ assert_return(ret, -EINVAL);
+ assert_return(s->type == SOURCE_INOTIFY, -EDOM);
+ assert_return(!event_origin_changed(s->event), -ECHILD);
+
+ if (!s->inotify.inode_data)
+ return -ESTALE; /* already disconnected. */
+
+ if (!s->inotify.inode_data->path)
+ return -ENOSYS; /* /proc was not mounted? */
+
+ *ret = s->inotify.inode_data->path;
return 0;
}
@@ -3999,7 +4035,7 @@ static int process_inotify(sd_event *e) {
if (r < 0)
return r;
if (r > 0)
- done ++;
+ done++;
}
return done;
@@ -4914,13 +4950,13 @@ _public_ int sd_event_get_state(sd_event *e) {
_public_ int sd_event_get_exit_code(sd_event *e, int *code) {
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(code, -EINVAL);
assert_return(!event_origin_changed(e), -ECHILD);
if (!e->exit_requested)
return -ENODATA;
- *code = e->exit_code;
+ if (code)
+ *code = e->exit_code;
return 0;
}
@@ -5037,7 +5073,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
}
}
- e->watchdog = !!b;
+ e->watchdog = b;
return e->watchdog;
fail:
diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c
index cc3d84e..57dee39 100644
--- a/src/libsystemd/sd-event/test-event.c
+++ b/src/libsystemd/sd-event/test-event.c
@@ -1,5 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#if HAVE_PIDFD_OPEN
+#include <sys/pidfd.h>
+#endif
#include <sys/wait.h>
#include <unistd.h>
@@ -92,7 +95,7 @@ static int signal_handler(sd_event_source *s, const struct signalfd_siginfo *si,
assert_se(userdata == INT_TO_PTR('e'));
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGUSR2) >= 0);
pid = fork();
assert_se(pid >= 0);
@@ -142,7 +145,7 @@ static int defer_handler(sd_event_source *s, void *userdata) {
assert_se(userdata == INT_TO_PTR('d'));
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGUSR1) >= 0);
assert_se(sd_event_add_signal(sd_event_source_get_event(s), &p, SIGUSR1, signal_handler, INT_TO_PTR('e')) >= 0);
assert_se(sd_event_source_set_enabled(p, SD_EVENT_ONESHOT) >= 0);
@@ -254,7 +257,7 @@ static void test_basic_one(bool with_pidfd) {
assert_se(sd_event_source_set_prepare(z, prepare_handler) >= 0);
/* Test for floating event sources */
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+1) >= 0);
assert_se(sd_event_add_signal(e, NULL, SIGRTMIN+1, NULL, NULL) >= 0);
assert_se(write(a[1], &ch, 1) >= 0);
@@ -346,7 +349,7 @@ TEST(rtqueue) {
assert_se(sd_event_default(&e) >= 0);
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2) >= 0);
assert_se(sd_event_add_signal(e, &u, SIGRTMIN+2, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &v, SIGRTMIN+3, rtqueue_handler, NULL) >= 0);
assert_se(sd_event_add_signal(e, &s, SIGUSR2, rtqueue_handler, NULL) >= 0);
@@ -396,6 +399,7 @@ struct inotify_context {
unsigned create_called[CREATE_EVENTS_MAX];
unsigned create_overflow;
unsigned n_create_events;
+ const char *path;
};
static void maybe_exit(sd_event_source *s, struct inotify_context *c) {
@@ -422,10 +426,12 @@ static void maybe_exit(sd_event_source *s, struct inotify_context *c) {
}
static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
- struct inotify_context *c = userdata;
- const char *description;
+ struct inotify_context *c = ASSERT_PTR(userdata);
+ const char *path, *description;
unsigned bit, n;
+ assert_se(sd_event_source_get_inotify_path(s, &path) >= 0);
+
assert_se(sd_event_source_get_description(s, &description) >= 0);
assert_se(safe_atou(description, &n) >= 0);
@@ -433,11 +439,12 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
bit = 1U << n;
if (ev->mask & IN_Q_OVERFLOW) {
- log_info("inotify-handler <%s>: overflow", description);
+ log_info("inotify-handler for %s <%s>: overflow", path, description);
c->create_overflow |= bit;
} else if (ev->mask & IN_CREATE) {
+ assert_se(path_equal_or_inode_same(path, c->path, 0));
if (streq(ev->name, "sub"))
- log_debug("inotify-handler <%s>: create on %s", description, ev->name);
+ log_debug("inotify-handler for %s <%s>: create on %s", path, description, ev->name);
else {
unsigned i;
@@ -446,7 +453,7 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
c->create_called[i] |= bit;
}
} else if (ev->mask & IN_DELETE) {
- log_info("inotify-handler <%s>: delete of %s", description, ev->name);
+ log_info("inotify-handler for %s <%s>: delete of %s", path, description, ev->name);
assert_se(streq(ev->name, "sub"));
} else
assert_not_reached();
@@ -456,16 +463,19 @@ static int inotify_handler(sd_event_source *s, const struct inotify_event *ev, v
}
static int delete_self_handler(sd_event_source *s, const struct inotify_event *ev, void *userdata) {
- struct inotify_context *c = userdata;
+ struct inotify_context *c = ASSERT_PTR(userdata);
+ const char *path;
+
+ assert_se(sd_event_source_get_inotify_path(s, &path) >= 0);
if (ev->mask & IN_Q_OVERFLOW) {
- log_info("delete-self-handler: overflow");
+ log_info("delete-self-handler for %s: overflow", path);
c->delete_self_handler_called = true;
} else if (ev->mask & IN_DELETE_SELF) {
- log_info("delete-self-handler: delete-self");
+ log_info("delete-self-handler for %s: delete-self", path);
c->delete_self_handler_called = true;
} else if (ev->mask & IN_IGNORED) {
- log_info("delete-self-handler: ignore");
+ log_info("delete-self-handler for %s: ignore", path);
} else
assert_not_reached();
@@ -480,7 +490,7 @@ static void test_inotify_one(unsigned n_create_events) {
.n_create_events = n_create_events,
};
sd_event *e = NULL;
- const char *q;
+ const char *q, *pp;
unsigned i;
log_info("/* %s(%u) */", __func__, n_create_events);
@@ -488,6 +498,7 @@ static void test_inotify_one(unsigned n_create_events) {
assert_se(sd_event_default(&e) >= 0);
assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0);
+ context.path = p;
assert_se(sd_event_add_inotify(e, &a, p, IN_CREATE|IN_ONLYDIR, inotify_handler, &context) >= 0);
assert_se(sd_event_add_inotify(e, &b, p, IN_CREATE|IN_DELETE|IN_DONT_FOLLOW, inotify_handler, &context) >= 0);
@@ -500,6 +511,13 @@ static void test_inotify_one(unsigned n_create_events) {
assert_se(sd_event_source_set_description(b, "1") >= 0);
assert_se(sd_event_source_set_description(c, "2") >= 0);
+ assert_se(sd_event_source_get_inotify_path(a, &pp) >= 0);
+ assert_se(path_equal_or_inode_same(pp, p, 0));
+ assert_se(sd_event_source_get_inotify_path(b, &pp) >= 0);
+ assert_se(path_equal_or_inode_same(pp, p, 0));
+ assert_se(sd_event_source_get_inotify_path(b, &pp) >= 0);
+ assert_se(path_equal_or_inode_same(pp, p, 0));
+
q = strjoina(p, "/sub");
assert_se(touch(q) >= 0);
assert_se(sd_event_add_inotify(e, &d, q, IN_DELETE_SELF, delete_self_handler, &context) >= 0);
@@ -556,7 +574,7 @@ TEST(pidfd) {
int pidfd;
pid_t pid, pid2;
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
+ assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD) >= 0);
pid = fork();
if (pid == 0)
diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c
index f163314..f623d47 100644
--- a/src/libsystemd/sd-hwdb/sd-hwdb.c
+++ b/src/libsystemd/sd-hwdb/sd-hwdb.c
@@ -313,15 +313,15 @@ static int hwdb_new(const char *path, sd_hwdb **ret) {
if (!hwdb->f)
return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
- "hwdb.bin does not exist, please run 'systemd-hwdb update'");
+ "hwdb.bin does not exist, please run 'systemd-hwdb update'.");
}
if (fstat(fileno(hwdb->f), &hwdb->st) < 0)
return log_debug_errno(errno, "Failed to stat %s: %m", path);
if (hwdb->st.st_size < (off_t) offsetof(struct trie_header_f, strings_len) + 8)
- return log_debug_errno(SYNTHETIC_ERRNO(EIO), "File %s is too short: %m", path);
+ return log_debug_errno(SYNTHETIC_ERRNO(EIO), "File %s is too short.", path);
if (file_offset_beyond_memory_size(hwdb->st.st_size))
- return log_debug_errno(SYNTHETIC_ERRNO(EFBIG), "File %s is too long: %m", path);
+ return log_debug_errno(SYNTHETIC_ERRNO(EFBIG), "File %s is too long.", path);
hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
if (hwdb->map == MAP_FAILED)
@@ -330,7 +330,7 @@ static int hwdb_new(const char *path, sd_hwdb **ret) {
if (memcmp(hwdb->map, sig, sizeof(hwdb->head->signature)) != 0 ||
(size_t) hwdb->st.st_size != le64toh(hwdb->head->file_size))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
- "Failed to recognize the format of %s", path);
+ "Failed to recognize the format of %s.", path);
log_debug("=== trie on-disk ===");
log_debug("tool version: %"PRIu64, le64toh(hwdb->head->tool_version));
diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c
index b9714ee..298d21e 100644
--- a/src/libsystemd/sd-id128/id128-util.c
+++ b/src/libsystemd/sd-id128/id128-util.c
@@ -9,9 +9,12 @@
#include "hexdecoct.h"
#include "id128-util.h"
#include "io-util.h"
+#include "namespace-util.h"
+#include "process-util.h"
#include "sha256.h"
#include "stdio-util.h"
#include "string-util.h"
+#include "strv.h"
#include "sync-util.h"
#include "virt.h"
@@ -192,11 +195,11 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
}
void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
- siphash24_compress(p, sizeof(sd_id128_t), state);
+ siphash24_compress_typesafe(*p, state);
}
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
- return memcmp(a, b, 16);
+ return memcmp(a, b, sizeof(sd_id128_t));
}
sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
@@ -231,11 +234,15 @@ int id128_get_product(sd_id128_t *ret) {
* of the host */
return -ENOENT;
- r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
- if (r == -ENOENT)
- r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
- if (r == -ENOENT)
- r = id128_read("/sys/hypervisor/uuid", ID128_FORMAT_UUID, &uuid);
+ FOREACH_STRING(i,
+ "/sys/class/dmi/id/product_uuid", /* KVM */
+ "/proc/device-tree/vm,uuid", /* Device tree */
+ "/sys/hypervisor/uuid") { /* Xen */
+
+ r = id128_read(i, ID128_FORMAT_UUID, &uuid);
+ if (r != -ENOENT)
+ break;
+ }
if (r < 0)
return r;
@@ -263,3 +270,64 @@ sd_id128_t id128_digest(const void *data, size_t size) {
return id128_make_v4_uuid(id);
}
+
+int id128_get_boot_for_machine(const char *machine, sd_id128_t *ret) {
+ _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, rootfd = -EBADF;
+ _cleanup_close_pair_ int pair[2] = EBADF_PAIR;
+ pid_t pid, child;
+ sd_id128_t id;
+ ssize_t k;
+ int r;
+
+ assert(ret);
+
+ if (isempty(machine))
+ return sd_id128_get_boot(ret);
+
+ r = container_get_leader(machine, &pid);
+ if (r < 0)
+ return r;
+
+ r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, /* ret_userns_fd = */ NULL, &rootfd);
+ if (r < 0)
+ return r;
+
+ if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
+ return -errno;
+
+ r = namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
+ pidnsfd, mntnsfd, -1, -1, rootfd, &child);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ pair[0] = safe_close(pair[0]);
+
+ r = id128_get_boot(&id);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ k = send(pair[1], &id, sizeof(id), MSG_NOSIGNAL);
+ if (k != sizeof(id))
+ _exit(EXIT_FAILURE);
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ pair[1] = safe_close(pair[1]);
+
+ r = wait_for_terminate_and_check("(sd-bootidns)", child, 0);
+ if (r < 0)
+ return r;
+ if (r != EXIT_SUCCESS)
+ return -EIO;
+
+ k = recv(pair[0], &id, sizeof(id), 0);
+ if (k != sizeof(id))
+ return -EIO;
+
+ if (sd_id128_is_null(id))
+ return -EIO;
+
+ *ret = id;
+ return 0;
+}
diff --git a/src/libsystemd/sd-id128/id128-util.h b/src/libsystemd/sd-id128/id128-util.h
index 53ba50a..458d430 100644
--- a/src/libsystemd/sd-id128/id128-util.h
+++ b/src/libsystemd/sd-id128/id128-util.h
@@ -49,6 +49,9 @@ int id128_get_product(sd_id128_t *ret);
sd_id128_t id128_digest(const void *data, size_t size);
+int id128_get_boot(sd_id128_t *ret);
+int id128_get_boot_for_machine(const char *machine, sd_id128_t *ret);
+
/* A helper to check for the three relevant cases of "machine ID not initialized" */
#define ERRNO_IS_NEG_MACHINE_ID_UNSET(r) \
IN_SET(r, \
diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c
index 9fda79a..fc1107b 100644
--- a/src/libsystemd/sd-id128/sd-id128.c
+++ b/src/libsystemd/sd-id128/sd-id128.c
@@ -13,6 +13,7 @@
#include "hmac.h"
#include "id128-util.h"
#include "io-util.h"
+#include "keyring-util.h"
#include "macro.h"
#include "missing_syscall.h"
#include "missing_threads.h"
@@ -170,14 +171,24 @@ int id128_get_machine(const char *root, sd_id128_t *ret) {
return id128_read_fd(fd, ID128_FORMAT_PLAIN | ID128_REFUSE_NULL, ret);
}
+int id128_get_boot(sd_id128_t *ret) {
+ int r;
+
+ assert(ret);
+
+ r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID | ID128_REFUSE_NULL, ret);
+ if (r == -ENOENT && proc_mounted() == 0)
+ return -ENOSYS;
+
+ return r;
+}
+
_public_ int sd_id128_get_boot(sd_id128_t *ret) {
static thread_local sd_id128_t saved_boot_id = {};
int r;
if (sd_id128_is_null(saved_boot_id)) {
- r = id128_read("/proc/sys/kernel/random/boot_id", ID128_FORMAT_UUID | ID128_REFUSE_NULL, &saved_boot_id);
- if (r == -ENOENT && proc_mounted() == 0)
- return -ENOSYS;
+ r = id128_get_boot(&saved_boot_id);
if (r < 0)
return r;
}
@@ -192,7 +203,6 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
char *d, *p, *g, *u, *e;
unsigned long perms;
key_serial_t key;
- size_t sz = 256;
uid_t uid;
gid_t gid;
int r, c;
@@ -211,24 +221,9 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
return -errno;
}
- for (;;) {
- description = new(char, sz);
- if (!description)
- return -ENOMEM;
-
- c = keyctl(KEYCTL_DESCRIBE, key, (unsigned long) description, sz, 0);
- if (c < 0)
- return -errno;
-
- if ((size_t) c <= sz)
- break;
-
- sz = c;
- free(description);
- }
-
- /* The kernel returns a final NUL in the string, verify that. */
- assert(description[c-1] == 0);
+ r = keyring_describe(key, &description);
+ if (r < 0)
+ return r;
/* Chop off the final description string */
d = strrchr(description, ';');
@@ -380,3 +375,16 @@ _public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret)
return sd_id128_get_app_specific(id, app_id, ret);
}
+
+_public_ int sd_id128_get_invocation_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
+ sd_id128_t id;
+ int r;
+
+ assert_return(ret, -EINVAL);
+
+ r = sd_id128_get_invocation(&id);
+ if (r < 0)
+ return r;
+
+ return sd_id128_get_app_specific(id, app_id, ret);
+}
diff --git a/src/libsystemd/sd-journal/catalog.c b/src/libsystemd/sd-journal/catalog.c
index ae91534..a0b673f 100644
--- a/src/libsystemd/sd-journal/catalog.c
+++ b/src/libsystemd/sd-journal/catalog.c
@@ -16,6 +16,7 @@
#include "conf-files.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "hashmap.h"
#include "log.h"
#include "memory-util.h"
@@ -54,7 +55,7 @@ typedef struct CatalogItem {
} CatalogItem;
static void catalog_hash_func(const CatalogItem *i, struct siphash *state) {
- siphash24_compress(&i->id, sizeof(i->id), state);
+ siphash24_compress_typesafe(i->id, state);
siphash24_compress_string(i->language, state);
}
@@ -222,10 +223,7 @@ static int catalog_entry_lang(
const char* deflang,
char **ret) {
- size_t c;
- char *z;
-
- c = strlen(t);
+ size_t c = strlen(t);
if (c < 2)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"[%s:%u] Language too short.", filename, line);
@@ -242,12 +240,7 @@ static int catalog_entry_lang(
log_warning("[%s:%u] language differs from default for file", filename, line);
}
- z = strdup(t);
- if (!z)
- return -ENOMEM;
-
- *ret = z;
- return 0;
+ return strdup_to(ret, t);
}
int catalog_import_file(OrderedHashmap *h, const char *path) {
@@ -382,10 +375,8 @@ static int64_t write_catalog(
CatalogItem *items,
size_t n) {
+ _cleanup_(unlink_and_freep) char *p = NULL;
_cleanup_fclose_ FILE *w = NULL;
- _cleanup_free_ char *p = NULL;
- CatalogHeader header;
- size_t k;
int r;
r = mkdir_parents(database, 0755);
@@ -394,54 +385,35 @@ static int64_t write_catalog(
r = fopen_temporary(database, &w, &p);
if (r < 0)
- return log_error_errno(r, "Failed to open database for writing: %s: %m",
- database);
+ return log_error_errno(r, "Failed to open database for writing: %s: %m", database);
- header = (CatalogHeader) {
+ CatalogHeader header = {
.signature = CATALOG_SIGNATURE,
.header_size = htole64(CONST_ALIGN_TO(sizeof(CatalogHeader), 8)),
.catalog_item_size = htole64(sizeof(CatalogItem)),
.n_items = htole64(n),
};
- r = -EIO;
+ if (fwrite(&header, sizeof(header), 1, w) != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "%s: failed to write header.", p);
- k = fwrite(&header, 1, sizeof(header), w);
- if (k != sizeof(header)) {
- log_error("%s: failed to write header.", p);
- goto error;
- }
+ if (fwrite(items, sizeof(CatalogItem), n, w) != n)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "%s: failed to write database.", p);
- k = fwrite(items, 1, n * sizeof(CatalogItem), w);
- if (k != n * sizeof(CatalogItem)) {
- log_error("%s: failed to write database.", p);
- goto error;
- }
-
- k = fwrite(sb->buf, 1, sb->len, w);
- if (k != sb->len) {
- log_error("%s: failed to write strings.", p);
- goto error;
- }
+ if (fwrite(sb->buf, sb->len, 1, w) != 1)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "%s: failed to write strings.", p);
r = fflush_and_check(w);
- if (r < 0) {
- log_error_errno(r, "%s: failed to write database: %m", p);
- goto error;
- }
+ if (r < 0)
+ return log_error_errno(r, "%s: failed to write database: %m", p);
(void) fchmod(fileno(w), 0644);
- if (rename(p, database) < 0) {
- r = log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
- goto error;
- }
+ if (rename(p, database) < 0)
+ return log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
+ p = mfree(p); /* free without unlinking */
return ftello(w);
-
-error:
- (void) unlink(p);
- return r;
}
int catalog_update(const char* database, const char* root, const char* const* dirs) {
@@ -472,11 +444,12 @@ int catalog_update(const char* database, const char* root, const char* const* di
return log_error_errno(r, "Failed to import file '%s': %m", *f);
}
- if (ordered_hashmap_size(h) <= 0) {
+ if (ordered_hashmap_isempty(h)) {
log_info("No items in catalog.");
return 0;
- } else
- log_debug("Found %u items in catalog.", ordered_hashmap_size(h));
+ }
+
+ log_debug("Found %u items in catalog.", ordered_hashmap_size(h));
items = new(CatalogItem, ordered_hashmap_size(h));
if (!items)
@@ -607,15 +580,14 @@ static const char *find_id(void *p, sd_id128_t id) {
le64toh(f->offset);
}
-int catalog_get(const char* database, sd_id128_t id, char **_text) {
+int catalog_get(const char* database, sd_id128_t id, char **ret_text) {
_cleanup_close_ int fd = -EBADF;
void *p = NULL;
- struct stat st = {};
- char *text = NULL;
+ struct stat st;
int r;
const char *s;
- assert(_text);
+ assert(ret_text);
r = open_mmap(database, &fd, &st, &p);
if (r < 0)
@@ -627,18 +599,9 @@ int catalog_get(const char* database, sd_id128_t id, char **_text) {
goto finish;
}
- text = strdup(s);
- if (!text) {
- r = -ENOMEM;
- goto finish;
- }
-
- *_text = text;
- r = 0;
-
+ r = strdup_to(ret_text, s);
finish:
- if (p)
- munmap(p, st.st_size);
+ (void) munmap(p, st.st_size);
return r;
}
diff --git a/src/libsystemd/sd-journal/catalog.h b/src/libsystemd/sd-journal/catalog.h
index df27869..b5a97fa 100644
--- a/src/libsystemd/sd-journal/catalog.h
+++ b/src/libsystemd/sd-journal/catalog.h
@@ -11,7 +11,7 @@
int catalog_import_file(OrderedHashmap *h, const char *path);
int catalog_update(const char* database, const char* root, const char* const* dirs);
-int catalog_get(const char* database, sd_id128_t id, char **data);
+int catalog_get(const char* database, sd_id128_t id, char **ret_text);
int catalog_list(FILE *f, const char* database, bool oneline);
int catalog_list_items(FILE *f, const char* database, bool oneline, char **items);
int catalog_file_lang(const char *filename, char **lang);
diff --git a/src/libsystemd/sd-journal/fsprg.c b/src/libsystemd/sd-journal/fsprg.c
index e86be6a..85632b0 100644
--- a/src/libsystemd/sd-journal/fsprg.c
+++ b/src/libsystemd/sd-journal/fsprg.c
@@ -3,21 +3,6 @@
* fsprg v0.1 - (seekable) forward-secure pseudorandom generator
* Copyright © 2012 B. Poettering
* Contact: fsprg@point-at-infinity.org
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA
*/
/*
@@ -50,11 +35,11 @@ static void mpi_export(void *buf, size_t buflen, const gcry_mpi_t x) {
unsigned len;
size_t nwritten;
- assert(gcry_mpi_cmp_ui(x, 0) >= 0);
- len = (gcry_mpi_get_nbits(x) + 7) / 8;
+ assert(sym_gcry_mpi_cmp_ui(x, 0) >= 0);
+ len = (sym_gcry_mpi_get_nbits(x) + 7) / 8;
assert(len <= buflen);
memzero(buf, buflen);
- gcry_mpi_print(GCRYMPI_FMT_USG, buf + (buflen - len), len, &nwritten, x);
+ sym_gcry_mpi_print(GCRYMPI_FMT_USG, buf + (buflen - len), len, &nwritten, x);
assert(nwritten == len);
}
@@ -62,10 +47,10 @@ static gcry_mpi_t mpi_import(const void *buf, size_t buflen) {
gcry_mpi_t h;
_unused_ unsigned len;
- assert_se(gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
- len = (gcry_mpi_get_nbits(h) + 7) / 8;
+ assert_se(sym_gcry_mpi_scan(&h, GCRYMPI_FMT_USG, buf, buflen, NULL) == 0);
+ len = (sym_gcry_mpi_get_nbits(h) + 7) / 8;
assert(len <= buflen);
- assert(gcry_mpi_cmp_ui(h, 0) >= 0);
+ assert(sym_gcry_mpi_cmp_ui(h, 0) >= 0);
return h;
}
@@ -102,30 +87,30 @@ static void det_randomize(void *buf, size_t buflen, const void *seed, size_t see
gcry_error_t err;
uint32_t ctr;
- olen = gcry_md_get_algo_dlen(RND_HASH);
- err = gcry_md_open(&hd, RND_HASH, 0);
+ olen = sym_gcry_md_get_algo_dlen(RND_HASH);
+ err = sym_gcry_md_open(&hd, RND_HASH, 0);
assert_se(gcry_err_code(err) == GPG_ERR_NO_ERROR); /* This shouldn't happen */
- gcry_md_write(hd, seed, seedlen);
- gcry_md_putc(hd, (idx >> 24) & 0xff);
- gcry_md_putc(hd, (idx >> 16) & 0xff);
- gcry_md_putc(hd, (idx >> 8) & 0xff);
- gcry_md_putc(hd, (idx >> 0) & 0xff);
+ sym_gcry_md_write(hd, seed, seedlen);
+ sym_gcry_md_putc(hd, (idx >> 24) & 0xff);
+ sym_gcry_md_putc(hd, (idx >> 16) & 0xff);
+ sym_gcry_md_putc(hd, (idx >> 8) & 0xff);
+ sym_gcry_md_putc(hd, (idx >> 0) & 0xff);
for (ctr = 0; buflen; ctr++) {
- err = gcry_md_copy(&hd2, hd);
+ err = sym_gcry_md_copy(&hd2, hd);
assert_se(gcry_err_code(err) == GPG_ERR_NO_ERROR); /* This shouldn't happen */
- gcry_md_putc(hd2, (ctr >> 24) & 0xff);
- gcry_md_putc(hd2, (ctr >> 16) & 0xff);
- gcry_md_putc(hd2, (ctr >> 8) & 0xff);
- gcry_md_putc(hd2, (ctr >> 0) & 0xff);
- gcry_md_final(hd2);
+ sym_gcry_md_putc(hd2, (ctr >> 24) & 0xff);
+ sym_gcry_md_putc(hd2, (ctr >> 16) & 0xff);
+ sym_gcry_md_putc(hd2, (ctr >> 8) & 0xff);
+ sym_gcry_md_putc(hd2, (ctr >> 0) & 0xff);
+ sym_gcry_md_ctl(hd2, GCRYCTL_FINALIZE, NULL, 0);
cpylen = (buflen < olen) ? buflen : olen;
- memcpy(buf, gcry_md_read(hd2, RND_HASH), cpylen);
- gcry_md_close(hd2);
+ memcpy(buf, sym_gcry_md_read(hd2, RND_HASH), cpylen);
+ sym_gcry_md_close(hd2);
buf += cpylen;
buflen -= cpylen;
}
- gcry_md_close(hd);
+ sym_gcry_md_close(hd);
}
/* deterministically generate from seed/idx a prime of length `bits' that is 3 (mod 4) */
@@ -142,8 +127,8 @@ static gcry_mpi_t genprime3mod4(int bits, const void *seed, size_t seedlen, uint
buf[buflen - 1] |= 0x03; /* set lower two bits, to have result 3 (mod 4) */
p = mpi_import(buf, buflen);
- while (gcry_prime_check(p, 0))
- gcry_mpi_add_ui(p, p, 4);
+ while (sym_gcry_prime_check(p, 0))
+ sym_gcry_mpi_add_ui(p, p, 4);
return p;
}
@@ -157,8 +142,8 @@ static gcry_mpi_t gensquare(const gcry_mpi_t n, const void *seed, size_t seedlen
det_randomize(buf, buflen, seed, seedlen, idx);
buf[0] &= 0x7f; /* clear upper bit, so that we have x < n */
x = mpi_import(buf, buflen);
- assert(gcry_mpi_cmp(x, n) < 0);
- gcry_mpi_mulm(x, x, x, n);
+ assert(sym_gcry_mpi_cmp(x, n) < 0);
+ sym_gcry_mpi_mulm(x, x, x, n);
return x;
}
@@ -167,51 +152,51 @@ static gcry_mpi_t twopowmodphi(uint64_t m, const gcry_mpi_t p) {
gcry_mpi_t phi, r;
int n;
- phi = gcry_mpi_new(0);
- gcry_mpi_sub_ui(phi, p, 1);
+ phi = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_sub_ui(phi, p, 1);
/* count number of used bits in m */
for (n = 0; (1ULL << n) <= m; n++)
;
- r = gcry_mpi_new(0);
- gcry_mpi_set_ui(r, 1);
+ r = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_set_ui(r, 1);
while (n) { /* square and multiply algorithm for fast exponentiation */
n--;
- gcry_mpi_mulm(r, r, r, phi);
+ sym_gcry_mpi_mulm(r, r, r, phi);
if (m & ((uint64_t)1 << n)) {
- gcry_mpi_add(r, r, r);
- if (gcry_mpi_cmp(r, phi) >= 0)
- gcry_mpi_sub(r, r, phi);
+ sym_gcry_mpi_add(r, r, r);
+ if (sym_gcry_mpi_cmp(r, phi) >= 0)
+ sym_gcry_mpi_sub(r, r, phi);
}
}
- gcry_mpi_release(phi);
+ sym_gcry_mpi_release(phi);
return r;
}
/* Decompose $x \in Z_n$ into $(xp,xq) \in Z_p \times Z_q$ using Chinese Remainder Theorem */
static void CRT_decompose(gcry_mpi_t *xp, gcry_mpi_t *xq, const gcry_mpi_t x, const gcry_mpi_t p, const gcry_mpi_t q) {
- *xp = gcry_mpi_new(0);
- *xq = gcry_mpi_new(0);
- gcry_mpi_mod(*xp, x, p);
- gcry_mpi_mod(*xq, x, q);
+ *xp = sym_gcry_mpi_new(0);
+ *xq = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_mod(*xp, x, p);
+ sym_gcry_mpi_mod(*xq, x, q);
}
/* Compose $(xp,xq) \in Z_p \times Z_q$ into $x \in Z_n$ using Chinese Remainder Theorem */
static void CRT_compose(gcry_mpi_t *x, const gcry_mpi_t xp, const gcry_mpi_t xq, const gcry_mpi_t p, const gcry_mpi_t q) {
gcry_mpi_t a, u;
- a = gcry_mpi_new(0);
- u = gcry_mpi_new(0);
- *x = gcry_mpi_new(0);
- gcry_mpi_subm(a, xq, xp, q);
- gcry_mpi_invm(u, p, q);
- gcry_mpi_mulm(a, a, u, q); /* a = (xq - xp) / p (mod q) */
- gcry_mpi_mul(*x, p, a);
- gcry_mpi_add(*x, *x, xp); /* x = p * ((xq - xp) / p mod q) + xp */
- gcry_mpi_release(a);
- gcry_mpi_release(u);
+ a = sym_gcry_mpi_new(0);
+ u = sym_gcry_mpi_new(0);
+ *x = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_subm(a, xq, xp, q);
+ sym_gcry_mpi_invm(u, p, q);
+ sym_gcry_mpi_mulm(a, a, u, q); /* a = (xq - xp) / p (mod q) */
+ sym_gcry_mpi_mul(*x, p, a);
+ sym_gcry_mpi_add(*x, *x, xp); /* x = p * ((xq - xp) / p mod q) + xp */
+ sym_gcry_mpi_release(a);
+ sym_gcry_mpi_release(u);
}
/******************************************************************************/
@@ -245,18 +230,21 @@ static uint16_t read_secpar(const void *buf) {
return 16 * (secpar + 1);
}
-void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned _secpar) {
+int FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned _secpar) {
uint8_t iseed[FSPRG_RECOMMENDED_SEEDLEN];
gcry_mpi_t n, p, q;
uint16_t secpar;
+ int r;
VALIDATE_SECPAR(_secpar);
secpar = _secpar;
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return r;
if (!seed) {
- gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM);
+ sym_gcry_randomize(iseed, FSPRG_RECOMMENDED_SEEDLEN, GCRY_STRONG_RANDOM);
seed = iseed;
seedlen = FSPRG_RECOMMENDED_SEEDLEN;
}
@@ -271,25 +259,30 @@ void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigne
}
if (mpk) {
- n = gcry_mpi_new(0);
- gcry_mpi_mul(n, p, q);
- assert(gcry_mpi_get_nbits(n) == secpar);
+ n = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_mul(n, p, q);
+ assert(sym_gcry_mpi_get_nbits(n) == secpar);
store_secpar(mpk + 0, secpar);
mpi_export(mpk + 2, secpar / 8, n);
- gcry_mpi_release(n);
+ sym_gcry_mpi_release(n);
}
- gcry_mpi_release(p);
- gcry_mpi_release(q);
+ sym_gcry_mpi_release(p);
+ sym_gcry_mpi_release(q);
+
+ return 0;
}
-void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen) {
+int FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen) {
gcry_mpi_t n, x;
uint16_t secpar;
+ int r;
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return r;
secpar = read_secpar(mpk + 0);
n = mpi_import(mpk + 2, secpar / 8);
@@ -299,30 +292,37 @@ void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seed
mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x);
memzero(state + 2 + 2 * secpar / 8, 8);
- gcry_mpi_release(n);
- gcry_mpi_release(x);
+ sym_gcry_mpi_release(n);
+ sym_gcry_mpi_release(x);
+
+ return 0;
}
-void FSPRG_Evolve(void *state) {
+int FSPRG_Evolve(void *state) {
gcry_mpi_t n, x;
uint16_t secpar;
uint64_t epoch;
+ int r;
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return r;
secpar = read_secpar(state + 0);
n = mpi_import(state + 2 + 0 * secpar / 8, secpar / 8);
x = mpi_import(state + 2 + 1 * secpar / 8, secpar / 8);
epoch = uint64_import(state + 2 + 2 * secpar / 8, 8);
- gcry_mpi_mulm(x, x, x, n);
+ sym_gcry_mpi_mulm(x, x, x, n);
epoch++;
mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, x);
uint64_export(state + 2 + 2 * secpar / 8, 8, epoch);
- gcry_mpi_release(n);
- gcry_mpi_release(x);
+ sym_gcry_mpi_release(n);
+ sym_gcry_mpi_release(x);
+
+ return 0;
}
uint64_t FSPRG_GetEpoch(const void *state) {
@@ -331,18 +331,21 @@ uint64_t FSPRG_GetEpoch(const void *state) {
return uint64_import(state + 2 + 2 * secpar / 8, 8);
}
-void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen) {
+int FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen) {
gcry_mpi_t p, q, n, x, xp, xq, kp, kq, xm;
uint16_t secpar;
+ int r;
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return r;
secpar = read_secpar(msk + 0);
p = mpi_import(msk + 2 + 0 * (secpar / 2) / 8, (secpar / 2) / 8);
q = mpi_import(msk + 2 + 1 * (secpar / 2) / 8, (secpar / 2) / 8);
- n = gcry_mpi_new(0);
- gcry_mpi_mul(n, p, q);
+ n = sym_gcry_mpi_new(0);
+ sym_gcry_mpi_mul(n, p, q);
x = gensquare(n, seed, seedlen, RND_GEN_X, secpar);
CRT_decompose(&xp, &xq, x, p, q); /* split (mod n) into (mod p) and (mod q) using CRT */
@@ -350,8 +353,8 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed,
kp = twopowmodphi(epoch, p); /* compute 2^epoch (mod phi(p)) */
kq = twopowmodphi(epoch, q); /* compute 2^epoch (mod phi(q)) */
- gcry_mpi_powm(xp, xp, kp, p); /* compute x^(2^epoch) (mod p) */
- gcry_mpi_powm(xq, xq, kq, q); /* compute x^(2^epoch) (mod q) */
+ sym_gcry_mpi_powm(xp, xp, kp, p); /* compute x^(2^epoch) (mod p) */
+ sym_gcry_mpi_powm(xq, xq, kq, q); /* compute x^(2^epoch) (mod q) */
CRT_compose(&xm, xp, xq, p, q); /* combine (mod p) and (mod q) to (mod n) using CRT */
@@ -360,22 +363,29 @@ void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed,
mpi_export(state + 2 + 1 * secpar / 8, secpar / 8, xm);
uint64_export(state + 2 + 2 * secpar / 8, 8, epoch);
- gcry_mpi_release(p);
- gcry_mpi_release(q);
- gcry_mpi_release(n);
- gcry_mpi_release(x);
- gcry_mpi_release(xp);
- gcry_mpi_release(xq);
- gcry_mpi_release(kp);
- gcry_mpi_release(kq);
- gcry_mpi_release(xm);
+ sym_gcry_mpi_release(p);
+ sym_gcry_mpi_release(q);
+ sym_gcry_mpi_release(n);
+ sym_gcry_mpi_release(x);
+ sym_gcry_mpi_release(xp);
+ sym_gcry_mpi_release(xq);
+ sym_gcry_mpi_release(kp);
+ sym_gcry_mpi_release(kq);
+ sym_gcry_mpi_release(xm);
+
+ return 0;
}
-void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) {
+int FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx) {
uint16_t secpar;
+ int r;
- initialize_libgcrypt(false);
+ r = initialize_libgcrypt(false);
+ if (r < 0)
+ return r;
secpar = read_secpar(state + 0);
det_randomize(key, keylen, state + 2, 2 * secpar / 8 + 8, idx);
+
+ return 0;
}
diff --git a/src/libsystemd/sd-journal/fsprg.h b/src/libsystemd/sd-journal/fsprg.h
index d3d88aa..a0594cd 100644
--- a/src/libsystemd/sd-journal/fsprg.h
+++ b/src/libsystemd/sd-journal/fsprg.h
@@ -5,21 +5,6 @@
* fsprg v0.1 - (seekable) forward-secure pseudorandom generator
* Copyright © 2012 B. Poettering
* Contact: fsprg@point-at-infinity.org
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301 USA
*/
#include <inttypes.h>
@@ -39,22 +24,22 @@ size_t FSPRG_mpkinbytes(unsigned secpar) _const_;
size_t FSPRG_stateinbytes(unsigned secpar) _const_;
/* Setup msk and mpk. Providing seed != NULL makes this algorithm deterministic. */
-void FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned secpar);
+int FSPRG_GenMK(void *msk, void *mpk, const void *seed, size_t seedlen, unsigned secpar);
/* Initialize state deterministically in dependence on seed. */
/* Note: in case one wants to run only one GenState0 per GenMK it is safe to use
the same seed for both GenMK and GenState0.
*/
-void FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen);
+int FSPRG_GenState0(void *state, const void *mpk, const void *seed, size_t seedlen);
-void FSPRG_Evolve(void *state);
+int FSPRG_Evolve(void *state);
uint64_t FSPRG_GetEpoch(const void *state) _pure_;
/* Seek to any arbitrary state (by providing msk together with seed from GenState0). */
-void FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen);
+int FSPRG_Seek(void *state, uint64_t epoch, const void *msk, const void *seed, size_t seedlen);
-void FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx);
+int FSPRG_GetKey(const void *state, void *key, size_t keylen, uint32_t idx);
#ifdef __cplusplus
}
diff --git a/src/libsystemd/sd-journal/journal-authenticate.c b/src/libsystemd/sd-journal/journal-authenticate.c
index 8e7533e..64f5739 100644
--- a/src/libsystemd/sd-journal/journal-authenticate.c
+++ b/src/libsystemd/sd-journal/journal-authenticate.c
@@ -71,7 +71,7 @@ int journal_file_append_tag(JournalFile *f) {
return r;
/* Get the HMAC tag and store it in the object */
- memcpy(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH);
+ memcpy(o->tag.tag, sym_gcry_md_read(f->hmac, 0), TAG_LENGTH);
f->hmac_running = false;
return 0;
@@ -80,6 +80,7 @@ int journal_file_append_tag(JournalFile *f) {
int journal_file_hmac_start(JournalFile *f) {
uint8_t key[256 / 8]; /* Let's pass 256 bit from FSPRG to HMAC */
gcry_error_t err;
+ int r;
assert(f);
@@ -90,13 +91,17 @@ int journal_file_hmac_start(JournalFile *f) {
return 0;
/* Prepare HMAC for next cycle */
- gcry_md_reset(f->hmac);
- FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
- err = gcry_md_setkey(f->hmac, key, sizeof(key));
+ sym_gcry_md_reset(f->hmac);
+
+ r = FSPRG_GetKey(f->fsprg_state, key, sizeof(key), 0);
+ if (r < 0)
+ return r;
+
+ err = sym_gcry_md_setkey(f->hmac, key, sizeof(key));
if (gcry_err_code(err) != GPG_ERR_NO_ERROR)
return log_debug_errno(SYNTHETIC_ERRNO(EIO),
- "gcry_md_setkey() failed with error code: %s",
- gcry_strerror(err));
+ "sym_gcry_md_setkey() failed with error code: %s",
+ sym_gcry_strerror(err));
f->hmac_running = true;
@@ -167,7 +172,10 @@ int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
if (epoch == goal)
return 0;
- FSPRG_Evolve(f->fsprg_state);
+ r = FSPRG_Evolve(f->fsprg_state);
+ if (r < 0)
+ return r;
+
epoch = FSPRG_GetEpoch(f->fsprg_state);
if (epoch < goal) {
r = journal_file_append_tag(f);
@@ -180,6 +188,7 @@ int journal_file_fsprg_evolve(JournalFile *f, uint64_t realtime) {
int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
void *msk;
uint64_t epoch;
+ int r;
assert(f);
@@ -195,10 +204,8 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
if (goal == epoch)
return 0;
- if (goal == epoch + 1) {
- FSPRG_Evolve(f->fsprg_state);
- return 0;
- }
+ if (goal == epoch + 1)
+ return FSPRG_Evolve(f->fsprg_state);
} else {
f->fsprg_state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
f->fsprg_state = malloc(f->fsprg_state_size);
@@ -209,10 +216,12 @@ int journal_file_fsprg_seek(JournalFile *f, uint64_t goal) {
log_debug("Seeking FSPRG key to %"PRIu64".", goal);
msk = alloca_safe(FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR));
- FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
- FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
- return 0;
+ r = FSPRG_GenMK(msk, NULL, f->fsprg_seed, f->fsprg_seed_size, FSPRG_RECOMMENDED_SECPAR);
+ if (r < 0)
+ return r;
+
+ return FSPRG_Seek(f->fsprg_state, goal, msk, f->fsprg_seed, f->fsprg_seed_size);
}
int journal_file_maybe_append_tag(JournalFile *f, uint64_t realtime) {
@@ -260,25 +269,25 @@ int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uin
} else if (type > OBJECT_UNUSED && o->object.type != type)
return -EBADMSG;
- gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
+ sym_gcry_md_write(f->hmac, o, offsetof(ObjectHeader, payload));
switch (o->object.type) {
case OBJECT_DATA:
/* All but hash and payload are mutable */
- gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
- gcry_md_write(f->hmac, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f));
+ sym_gcry_md_write(f->hmac, &o->data.hash, sizeof(o->data.hash));
+ sym_gcry_md_write(f->hmac, journal_file_data_payload_field(f, o), le64toh(o->object.size) - journal_file_data_payload_offset(f));
break;
case OBJECT_FIELD:
/* Same here */
- gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash));
- gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
+ sym_gcry_md_write(f->hmac, &o->field.hash, sizeof(o->field.hash));
+ sym_gcry_md_write(f->hmac, o->field.payload, le64toh(o->object.size) - offsetof(Object, field.payload));
break;
case OBJECT_ENTRY:
/* All */
- gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum));
+ sym_gcry_md_write(f->hmac, &o->entry.seqnum, le64toh(o->object.size) - offsetof(Object, entry.seqnum));
break;
case OBJECT_FIELD_HASH_TABLE:
@@ -289,8 +298,8 @@ int journal_file_hmac_put_object(JournalFile *f, ObjectType type, Object *o, uin
case OBJECT_TAG:
/* All but the tag itself */
- gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
- gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
+ sym_gcry_md_write(f->hmac, &o->tag.seqnum, sizeof(o->tag.seqnum));
+ sym_gcry_md_write(f->hmac, &o->tag.epoch, sizeof(o->tag.epoch));
break;
default:
return -EINVAL;
@@ -318,10 +327,10 @@ int journal_file_hmac_put_header(JournalFile *f) {
* tail_entry_monotonic, n_data, n_fields, n_tags,
* n_entry_arrays. */
- gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
- gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id));
- gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
- gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
+ sym_gcry_md_write(f->hmac, f->header->signature, offsetof(Header, state) - offsetof(Header, signature));
+ sym_gcry_md_write(f->hmac, &f->header->file_id, offsetof(Header, tail_entry_boot_id) - offsetof(Header, file_id));
+ sym_gcry_md_write(f->hmac, &f->header->seqnum_id, offsetof(Header, arena_size) - offsetof(Header, seqnum_id));
+ sym_gcry_md_write(f->hmac, &f->header->data_hash_table_offset, offsetof(Header, tail_object_offset) - offsetof(Header, data_hash_table_offset));
return 0;
}
@@ -406,13 +415,16 @@ int journal_file_fss_load(JournalFile *f) {
int journal_file_hmac_setup(JournalFile *f) {
gcry_error_t e;
+ int r;
if (!JOURNAL_HEADER_SEALED(f->header))
return 0;
- initialize_libgcrypt(true);
+ r = initialize_libgcrypt(true);
+ if (r < 0)
+ return r;
- e = gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
+ e = sym_gcry_md_open(&f->hmac, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
if (e != 0)
return -EOPNOTSUPP;
diff --git a/src/libsystemd/sd-journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c
index 08cbf86..7e941ed 100644
--- a/src/libsystemd/sd-journal/journal-file.c
+++ b/src/libsystemd/sd-journal/journal-file.c
@@ -20,6 +20,7 @@
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
+#include "gcrypt-util.h"
#include "id128-util.h"
#include "journal-authenticate.h"
#include "journal-def.h"
@@ -47,10 +48,6 @@
#define DEFAULT_COMPRESS_THRESHOLD (512ULL)
#define MIN_COMPRESS_THRESHOLD (8ULL)
-#define U64_KB UINT64_C(1024)
-#define U64_MB (UINT64_C(1024) * U64_KB)
-#define U64_GB (UINT64_C(1024) * U64_MB)
-
/* This is the minimum journal file size */
#define JOURNAL_FILE_SIZE_MIN (512 * U64_KB) /* 512 KiB */
#define JOURNAL_COMPACT_SIZE_MAX ((uint64_t) UINT32_MAX) /* 4 GiB */
@@ -285,6 +282,8 @@ JournalFile* journal_file_close(JournalFile *f) {
assert(f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL);
+ sd_event_source_disable_unref(f->post_change_timer);
+
if (f->cache_fd)
mmap_cache_fd_free(f->cache_fd);
@@ -309,7 +308,7 @@ JournalFile* journal_file_close(JournalFile *f) {
free(f->fsprg_seed);
if (f->hmac)
- gcry_md_close(f->hmac);
+ sym_gcry_md_close(f->hmac);
#endif
return mfree(f);
@@ -2249,7 +2248,6 @@ static int journal_file_link_entry(
f->header->tail_entry_monotonic = o->entry.monotonic;
if (JOURNAL_HEADER_CONTAINS(f->header, tail_entry_offset))
f->header->tail_entry_offset = htole64(offset);
- f->newest_mtime = 0; /* we have a new tail entry now, explicitly invalidate newest boot id/timestamp info */
/* Link up the items */
for (uint64_t i = 0; i < n_items; i++) {
@@ -2762,7 +2760,7 @@ static int generic_array_get(
Object **ret_object, /* The found object. */
uint64_t *ret_offset) { /* The offset of the found object. */
- uint64_t a, t = 0, k;
+ uint64_t a, t = 0, k = 0; /* Explicit initialization of k to appease gcc */
ChainCacheItem *ci;
Object *o = NULL;
int r;
@@ -3052,7 +3050,7 @@ static int generic_array_bisect(
left = 0;
right = m - 1;
- if (direction == DIRECTION_UP) {
+ if (direction == DIRECTION_UP && left < right) {
/* If we're going upwards, the last entry of the previous array may pass the test,
* and the first entry of the current array may not pass. In that case, the last
* entry of the previous array must be returned. Hence, we need to test the first
@@ -3167,10 +3165,21 @@ previous:
if (direction == DIRECTION_DOWN)
return 0;
- /* Indicate to go to the previous array later. Note, do not move to the previous array here,
- * as that may invalidate the current array object in the mmap cache and
- * journal_file_entry_array_item() below may read invalid address. */
- i = UINT64_MAX;
+ /* Get the last entry of the previous array. */
+ r = bump_entry_array(f, NULL, a, first, DIRECTION_UP, &a);
+ if (r <= 0)
+ return r;
+
+ r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
+ if (r < 0)
+ return r;
+
+ p = journal_file_entry_array_n_items(f, array);
+ if (p == 0 || t < p)
+ return -EBADMSG;
+
+ t -= p;
+ i = p - 1;
found:
p = journal_file_entry_array_item(f, array, 0);
@@ -3180,27 +3189,6 @@ found:
/* Let's cache this item for the next invocation */
chain_cache_put(f->chain_cache, ci, first, a, p, t, i);
- if (i == UINT64_MAX) {
- uint64_t m;
-
- /* Get the last entry of the previous array. */
-
- r = bump_entry_array(f, NULL, a, first, DIRECTION_UP, &a);
- if (r <= 0)
- return r;
-
- r = journal_file_move_to_object(f, OBJECT_ENTRY_ARRAY, a, &array);
- if (r < 0)
- return r;
-
- m = journal_file_entry_array_n_items(f, array);
- if (m == 0 || t < m)
- return -EBADMSG;
-
- t -= m;
- i = m - 1;
- }
-
p = journal_file_entry_array_item(f, array, i);
if (p == 0)
return -EBADMSG;
@@ -3267,7 +3255,7 @@ static int generic_array_bisect_for_data(
} else {
/* If we are going upwards, then we need to return the last object that passes the test.
- * When there is no object that passes the test, we need to return the the last object that
+ * When there is no object that passes the test, we need to return the last object that
* test_object() returns TEST_LEFT for. */
if (r == TEST_RIGHT)
return 0; /* Not only the 'extra' object, but also all objects in the chained arrays
@@ -3554,7 +3542,8 @@ int journal_file_next_entry(
p,
test_object_offset,
direction,
- ret_object ? &o : NULL, &q, &i);
+ NULL, &q, &i); /* Here, do not read entry object, as the result object
+ * may not be the one we want, and it may be broken. */
if (r <= 0)
return r;
@@ -3564,12 +3553,11 @@ int journal_file_next_entry(
* the same offset, and the index needs to be shifted. Otherwise, use the found object as is,
* as it is the nearest entry object from the input offset 'p'. */
- if (p != q)
- goto found;
-
- r = bump_array_index(&i, direction, n);
- if (r <= 0)
- return r;
+ if (p == q) {
+ r = bump_array_index(&i, direction, n);
+ if (r <= 0)
+ return r;
+ }
/* And jump to it */
r = generic_array_get(f, le64toh(f->header->entry_array_offset), i, direction, ret_object ? &o : NULL, &q);
@@ -3581,7 +3569,7 @@ int journal_file_next_entry(
return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
"%s: entry array not properly ordered at entry index %" PRIu64,
f->path, i);
-found:
+
if (ret_object)
*ret_object = o;
if (ret_offset)
@@ -3813,35 +3801,35 @@ void journal_file_dump(JournalFile *f) {
case OBJECT_ENTRY:
assert(s);
- printf("Type: %s seqnum=%"PRIu64" monotonic=%"PRIu64" realtime=%"PRIu64"\n",
- s,
- le64toh(o->entry.seqnum),
- le64toh(o->entry.monotonic),
- le64toh(o->entry.realtime));
+ log_info("Type: %s seqnum=%"PRIu64" monotonic=%"PRIu64" realtime=%"PRIu64"\n",
+ s,
+ le64toh(o->entry.seqnum),
+ le64toh(o->entry.monotonic),
+ le64toh(o->entry.realtime));
break;
case OBJECT_TAG:
assert(s);
- printf("Type: %s seqnum=%"PRIu64" epoch=%"PRIu64"\n",
- s,
- le64toh(o->tag.seqnum),
- le64toh(o->tag.epoch));
+ log_info("Type: %s seqnum=%"PRIu64" epoch=%"PRIu64"\n",
+ s,
+ le64toh(o->tag.seqnum),
+ le64toh(o->tag.epoch));
break;
default:
if (s)
- printf("Type: %s \n", s);
+ log_info("Type: %s \n", s);
else
- printf("Type: unknown (%i)", o->object.type);
+ log_info("Type: unknown (%i)", o->object.type);
break;
}
c = COMPRESSION_FROM_OBJECT(o);
if (c > COMPRESSION_NONE)
- printf("Flags: %s\n",
- compression_to_string(c));
+ log_info("Flags: %s\n",
+ compression_to_string(c));
if (p == le64toh(f->header->tail_object_offset))
p = 0;
@@ -4374,11 +4362,9 @@ int journal_file_archive(JournalFile *f, char **ret_previous_path) {
(void) fsync_directory_of_file(f->fd);
if (ret_previous_path)
- *ret_previous_path = f->path;
- else
- free(f->path);
+ *ret_previous_path = TAKE_PTR(f->path);
- f->path = TAKE_PTR(p);
+ free_and_replace(f->path, p);
/* Set as archive so offlining commits w/state=STATE_ARCHIVED. Previously we would set old_file->header->state
* to STATE_ARCHIVED directly here, but journal_file_set_offline() short-circuits when state != STATE_ONLINE,
diff --git a/src/libsystemd/sd-journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h
index 81fafb9..8100388 100644
--- a/src/libsystemd/sd-journal/journal-file.h
+++ b/src/libsystemd/sd-journal/journal-file.h
@@ -129,7 +129,8 @@ typedef struct JournalFile {
uint64_t newest_monotonic_usec;
uint64_t newest_realtime_usec;
unsigned newest_boot_id_prioq_idx;
- usec_t newest_mtime;
+ uint64_t newest_entry_offset;
+ uint8_t newest_state;
} JournalFile;
typedef enum JournalFileFlags {
@@ -309,7 +310,6 @@ void journal_file_print_header(JournalFile *f);
int journal_file_archive(JournalFile *f, char **ret_previous_path);
int journal_file_parse_uid_from_filename(const char *path, uid_t *uid);
-JournalFile* journal_initiate_close(JournalFile *f, Set *deferred_closes);
int journal_file_dispose(int dir_fd, const char *fname);
diff --git a/src/libsystemd/sd-journal/journal-internal.h b/src/libsystemd/sd-journal/journal-internal.h
index 259aac8..b95080c 100644
--- a/src/libsystemd/sd-journal/journal-internal.h
+++ b/src/libsystemd/sd-journal/journal-internal.h
@@ -12,7 +12,7 @@
#include "journal-def.h"
#include "journal-file.h"
#include "list.h"
-#include "set.h"
+#include "prioq.h"
#define JOURNAL_FILES_MAX 7168u
@@ -62,12 +62,18 @@ struct Location {
};
struct Directory {
+ sd_journal *journal;
char *path;
int wd;
bool is_root;
unsigned last_seen_generation;
};
+typedef struct NewestByBootId {
+ sd_id128_t boot_id;
+ Prioq *prioq; /* JournalFile objects ordered by monotonic timestamp of last update. */
+} NewestByBootId;
+
struct sd_journal {
int toplevel_fd;
@@ -78,7 +84,10 @@ struct sd_journal {
OrderedHashmap *files;
IteratedCache *files_cache;
MMapCache *mmap;
- Hashmap *newest_by_boot_id; /* key: boot_id, value: prioq, ordered by monotonic timestamp of last update */
+
+ /* a bisectable array of NewestByBootId, ordered by boot id. */
+ NewestByBootId *newest_by_boot_id;
+ size_t n_newest_by_boot_id;
Location current_location;
@@ -86,6 +95,7 @@ struct sd_journal {
uint64_t current_field;
Match *level0, *level1, *level2;
+ Set *exclude_syslog_identifiers;
uint64_t origin_id;
@@ -128,6 +138,10 @@ struct sd_journal {
char *journal_make_match_string(sd_journal *j);
void journal_print_header(sd_journal *j);
+int journal_get_directories(sd_journal *j, char ***ret);
+
+int journal_add_match_pair(sd_journal *j, const char *field, const char *value);
+int journal_add_matchf(sd_journal *j, const char *format, ...) _printf_(2, 3);
#define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval) \
for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; )
diff --git a/src/libsystemd/sd-journal/journal-send.c b/src/libsystemd/sd-journal/journal-send.c
index be23b2f..7d02b57 100644
--- a/src/libsystemd/sd-journal/journal-send.c
+++ b/src/libsystemd/sd-journal/journal-send.c
@@ -121,7 +121,7 @@ _public_ int sd_journal_printv(int priority, const char *format, va_list ap) {
assert_return(priority <= 7, -EINVAL);
assert_return(format, -EINVAL);
- xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
+ xsprintf(p, "PRIORITY=%i", LOG_PRI(priority));
va_copy(aq, ap);
len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
@@ -398,20 +398,28 @@ _public_ int sd_journal_perror(const char *message) {
return fill_iovec_perror_and_send(message, 0, iovec);
}
-_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
+_public_ int sd_journal_stream_fd_with_namespace(
+ const char *name_space,
+ const char *identifier,
+ int priority,
+ int level_prefix) {
+
_cleanup_close_ int fd = -EBADF;
- char *header;
- size_t l;
+ const char *path;
int r;
assert_return(priority >= 0, -EINVAL);
assert_return(priority <= 7, -EINVAL);
+ path = journal_stream_path(name_space);
+ if (!path)
+ return -EINVAL;
+
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0);
if (fd < 0)
return -errno;
- r = connect_unix_path(fd, AT_FDCWD, "/run/systemd/journal/stdout");
+ r = connect_unix_path(fd, AT_FDCWD, path);
if (r < 0)
return r;
@@ -422,6 +430,9 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
identifier = strempty(identifier);
+ char *header;
+ size_t l;
+
l = strlen(identifier);
header = newa(char, l + 1 + 1 + 2 + 2 + 2 + 2 + 2);
@@ -446,6 +457,10 @@ _public_ int sd_journal_stream_fd(const char *identifier, int priority, int leve
return TAKE_FD(fd);
}
+_public_ int sd_journal_stream_fd(const char *identifier, int priority, int level_prefix) {
+ return sd_journal_stream_fd_with_namespace(NULL, identifier, priority, level_prefix);
+}
+
_public_ int sd_journal_print_with_location(int priority, const char *file, const char *line, const char *func, const char *format, ...) {
int r;
va_list ap;
@@ -470,7 +485,7 @@ _public_ int sd_journal_printv_with_location(int priority, const char *file, con
assert_return(priority <= 7, -EINVAL);
assert_return(format, -EINVAL);
- xsprintf(p, "PRIORITY=%i", priority & LOG_PRIMASK);
+ xsprintf(p, "PRIORITY=%i", LOG_PRI(priority));
va_copy(aq, ap);
len = vsnprintf(buffer + 8, LINE_MAX, format, aq);
diff --git a/src/libsystemd/sd-journal/journal-send.h b/src/libsystemd/sd-journal/journal-send.h
index 24315e2..6fe6325 100644
--- a/src/libsystemd/sd-journal/journal-send.h
+++ b/src/libsystemd/sd-journal/journal-send.h
@@ -2,6 +2,23 @@
#pragma once
#include <stdbool.h>
+#include <stddef.h>
+
+#include "syslog-util.h"
int journal_fd_nonblock(bool nonblock);
void close_journal_fd(void);
+
+/* We declare sd_journal_stream_fd() as async-signal-safe. So instead of strjoin(), which calls malloc()
+ * internally, use a macro + alloca(). */
+#define journal_stream_path(log_namespace) \
+ ({ \
+ const char *_ns = (log_namespace), *_ret; \
+ if (!_ns) \
+ _ret = "/run/systemd/journal/stdout"; \
+ else if (log_namespace_name_valid(_ns)) \
+ _ret = strjoina("/run/systemd/journal.", _ns, "/stdout"); \
+ else \
+ _ret = NULL; \
+ _ret; \
+ })
diff --git a/src/libsystemd/sd-journal/journal-verify.c b/src/libsystemd/sd-journal/journal-verify.c
index b5ce55a..e852591 100644
--- a/src/libsystemd/sd-journal/journal-verify.c
+++ b/src/libsystemd/sd-journal/journal-verify.c
@@ -10,6 +10,7 @@
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "gcrypt-util.h"
#include "journal-authenticate.h"
#include "journal-def.h"
#include "journal-file.h"
@@ -1224,7 +1225,7 @@ int journal_file_verify(
if (r < 0)
goto fail;
- if (memcmp(o->tag.tag, gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
+ if (memcmp(o->tag.tag, sym_gcry_md_read(f->hmac, 0), TAG_LENGTH) != 0) {
error(p, "Tag failed verification");
r = -EBADMSG;
goto fail;
diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c
index ca1ef0c..0aa3726 100644
--- a/src/libsystemd/sd-journal/sd-journal.c
+++ b/src/libsystemd/sd-journal/sd-journal.c
@@ -38,12 +38,13 @@
#include "prioq.h"
#include "process-util.h"
#include "replace-var.h"
+#include "sort-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "strv.h"
#include "syslog-util.h"
-#include "uid-alloc-range.h"
+#include "uid-classification.h"
#define JOURNAL_FILES_RECHECK_USEC (2 * USEC_PER_SEC)
@@ -232,7 +233,11 @@ _public_ int sd_journal_add_match(sd_journal *j, const void *data, size_t size)
assert_return(!journal_origin_changed(j), -ECHILD);
assert_return(data, -EINVAL);
- if (size == 0)
+ /* If the size is unspecified, assume it's a string. Note: 0 is the public value we document for
+ * this, for historical reasons. Internally, we pretty widely started using SIZE_MAX for this in
+ * similar cases however, hence accept that too. And internally we actually prefer it, to make things
+ * less surprising. */
+ if (IN_SET(size, 0, SIZE_MAX))
size = strlen(data);
if (!match_is_valid(data, size))
@@ -324,6 +329,37 @@ fail:
return -ENOMEM;
}
+int journal_add_match_pair(sd_journal *j, const char *field, const char *value) {
+ _cleanup_free_ char *s = NULL;
+
+ assert(j);
+ assert(field);
+ assert(value);
+
+ s = strjoin(field, "=", value);
+ if (!s)
+ return -ENOMEM;
+
+ return sd_journal_add_match(j, s, SIZE_MAX);
+}
+
+int journal_add_matchf(sd_journal *j, const char *format, ...) {
+ _cleanup_free_ char *s = NULL;
+ va_list ap;
+ int r;
+
+ assert(j);
+ assert(format);
+
+ va_start(ap, format);
+ r = vasprintf(&s, format, ap);
+ va_end(ap);
+ if (r < 0)
+ return -ENOMEM;
+
+ return sd_journal_add_match(j, s, SIZE_MAX);
+}
+
_public_ int sd_journal_add_conjunction(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_origin_changed(j), -ECHILD);
@@ -413,6 +449,99 @@ _public_ void sd_journal_flush_matches(sd_journal *j) {
detach_location(j);
}
+static int newest_by_boot_id_compare(const NewestByBootId *a, const NewestByBootId *b) {
+ return id128_compare_func(&a->boot_id, &b->boot_id);
+}
+
+static void journal_file_unlink_newest_by_boot_id(sd_journal *j, JournalFile *f) {
+ NewestByBootId *found;
+
+ assert(j);
+ assert(f);
+
+ if (f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL) /* not linked currently, hence this is a NOP */
+ return;
+
+ found = typesafe_bsearch(&(NewestByBootId) { .boot_id = f->newest_boot_id },
+ j->newest_by_boot_id, j->n_newest_by_boot_id, newest_by_boot_id_compare);
+ assert(found);
+
+ assert_se(prioq_remove(found->prioq, f, &f->newest_boot_id_prioq_idx) > 0);
+ f->newest_boot_id_prioq_idx = PRIOQ_IDX_NULL;
+
+ /* The prioq may be empty, but that should not cause any issue. Let's keep it. */
+}
+
+static void journal_clear_newest_by_boot_id(sd_journal *j) {
+ FOREACH_ARRAY(i, j->newest_by_boot_id, j->n_newest_by_boot_id) {
+ JournalFile *f;
+
+ while ((f = prioq_peek(i->prioq)))
+ journal_file_unlink_newest_by_boot_id(j, f);
+
+ prioq_free(i->prioq);
+ }
+
+ j->newest_by_boot_id = mfree(j->newest_by_boot_id);
+ j->n_newest_by_boot_id = 0;
+}
+
+static int journal_file_newest_monotonic_compare(const void *a, const void *b) {
+ const JournalFile *x = a, *y = b;
+
+ return -CMP(x->newest_monotonic_usec, y->newest_monotonic_usec); /* Invert order, we want newest first! */
+}
+
+static int journal_file_reshuffle_newest_by_boot_id(sd_journal *j, JournalFile *f) {
+ NewestByBootId *found;
+ int r;
+
+ assert(j);
+ assert(f);
+
+ found = typesafe_bsearch(&(NewestByBootId) { .boot_id = f->newest_boot_id },
+ j->newest_by_boot_id, j->n_newest_by_boot_id, newest_by_boot_id_compare);
+ if (found) {
+ /* There's already a priority queue for this boot ID */
+
+ if (f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL) {
+ r = prioq_put(found->prioq, f, &f->newest_boot_id_prioq_idx); /* Insert if we aren't in there yet */
+ if (r < 0)
+ return r;
+ } else
+ prioq_reshuffle(found->prioq, f, &f->newest_boot_id_prioq_idx); /* Reshuffle otherwise */
+
+ } else {
+ _cleanup_(prioq_freep) Prioq *q = NULL;
+
+ /* No priority queue yet, then allocate one */
+
+ assert(f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL); /* we can't be a member either */
+
+ q = prioq_new(journal_file_newest_monotonic_compare);
+ if (!q)
+ return -ENOMEM;
+
+ r = prioq_put(q, f, &f->newest_boot_id_prioq_idx);
+ if (r < 0)
+ return r;
+
+ if (!GREEDY_REALLOC(j->newest_by_boot_id, j->n_newest_by_boot_id + 1)) {
+ f->newest_boot_id_prioq_idx = PRIOQ_IDX_NULL;
+ return -ENOMEM;
+ }
+
+ j->newest_by_boot_id[j->n_newest_by_boot_id++] = (NewestByBootId) {
+ .boot_id = f->newest_boot_id,
+ .prioq = TAKE_PTR(q),
+ };
+
+ typesafe_qsort(j->newest_by_boot_id, j->n_newest_by_boot_id, newest_by_boot_id_compare);
+ }
+
+ return 0;
+}
+
static int journal_file_find_newest_for_boot_id(
sd_journal *j,
sd_id128_t id,
@@ -427,16 +556,17 @@ static int journal_file_find_newest_for_boot_id(
/* Before we use it, let's refresh the timestamp from the header, and reshuffle our prioq
* accordingly. We do this only a bunch of times, to not be caught in some update loop. */
for (unsigned n_tries = 0;; n_tries++) {
+ NewestByBootId *found;
JournalFile *f;
- Prioq *q;
- q = hashmap_get(j->newest_by_boot_id, &id);
- if (!q)
+ found = typesafe_bsearch(&(NewestByBootId) { .boot_id = id },
+ j->newest_by_boot_id, j->n_newest_by_boot_id, newest_by_boot_id_compare);
+
+ f = found ? prioq_peek(found->prioq) : NULL;
+ if (!f)
return log_debug_errno(SYNTHETIC_ERRNO(ENODATA),
"Requested delta for boot ID %s, but we have no information about that boot ID.", SD_ID128_TO_STRING(id));
- assert_se(f = prioq_peek(q)); /* we delete hashmap entries once the prioq is empty, so this must hold */
-
if (f == prev || n_tries >= 5) {
/* This was already the best answer in the previous run, or we tried too often, use it */
*ret = f;
@@ -449,6 +579,11 @@ static int journal_file_find_newest_for_boot_id(
r = journal_file_read_tail_timestamp(j, f);
if (r < 0)
return log_debug_errno(r, "Failed to read tail timestamp while trying to find newest journal file for boot ID %s.", SD_ID128_TO_STRING(id));
+ if (r == 0) {
+ /* No new entry found. */
+ *ret = f;
+ return 0;
+ }
/* Refreshing the timestamp we read might have reshuffled the prioq, hence let's check the
* prioq again and only use the information once we reached an equilibrium or hit a limit */
@@ -932,8 +1067,8 @@ static int real_journal_next(sd_journal *j, direction_t direction) {
if (r < 0)
return r;
- for (unsigned i = 0; i < n_files; i++) {
- JournalFile *f = (JournalFile *)files[i];
+ FOREACH_ARRAY(_f, files, n_files) {
+ JournalFile *f = (JournalFile*) *_f;
bool found;
r = next_beyond_location(j, f, direction);
@@ -1373,17 +1508,6 @@ static void track_file_disposition(sd_journal *j, JournalFile *f) {
j->has_persistent_files = true;
}
-static const char *skip_slash(const char *p) {
-
- if (!p)
- return NULL;
-
- while (*p == '/')
- p++;
-
- return p;
-}
-
static int add_any_file(
sd_journal *j,
int fd,
@@ -1403,7 +1527,7 @@ static int add_any_file(
/* If there's a top-level fd defined make the path relative, explicitly, since otherwise
* openat() ignores the first argument. */
- fd = our_fd = openat(j->toplevel_fd, skip_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ fd = our_fd = openat(j->toplevel_fd, skip_leading_slash(path), O_RDONLY|O_CLOEXEC|O_NONBLOCK);
else
fd = our_fd = open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (fd < 0) {
@@ -1494,6 +1618,41 @@ error:
return r;
}
+int journal_get_directories(sd_journal *j, char ***ret) {
+ _cleanup_strv_free_ char **paths = NULL;
+ JournalFile *f;
+ const char *p;
+ size_t n = SIZE_MAX;
+ int r;
+
+ assert(j);
+ assert(ret);
+
+ /* This returns parent directories of opened journal files. */
+
+ ORDERED_HASHMAP_FOREACH_KEY(f, p, j->files) {
+ _cleanup_free_ char *d = NULL;
+
+ /* Ignore paths generated from fd. */
+ if (path_startswith(p, "/proc/"))
+ continue;
+
+ r = path_extract_directory(p, &d);
+ if (r < 0)
+ return r;
+
+ if (path_strv_contains(paths, d))
+ continue;
+
+ r = strv_extend_with_size(&paths, &n, d);
+ if (r < 0)
+ return r;
+ }
+
+ *ret = TAKE_PTR(paths);
+ return 0;
+}
+
static int add_file_by_name(
sd_journal *j,
const char *prefix,
@@ -1676,7 +1835,7 @@ static int directory_open(sd_journal *j, const char *path, DIR **ret) {
else
/* Open the specified directory relative to the toplevel fd. Enforce that the path specified is
* relative, by dropping the initial slash */
- d = xopendirat(j->toplevel_fd, skip_slash(path), 0);
+ d = xopendirat(j->toplevel_fd, skip_leading_slash(path), 0);
if (!d)
return -errno;
@@ -1684,6 +1843,100 @@ static int directory_open(sd_journal *j, const char *path, DIR **ret) {
return 0;
}
+static Directory* directory_free(Directory *d) {
+ if (!d)
+ return NULL;
+
+ if (d->journal) {
+ if (d->wd > 0 &&
+ hashmap_remove_value(d->journal->directories_by_wd, INT_TO_PTR(d->wd), d) &&
+ d->journal->inotify_fd >= 0)
+ (void) inotify_rm_watch(d->journal->inotify_fd, d->wd);
+
+ if (d->path)
+ hashmap_remove_value(d->journal->directories_by_path, d->path, d);
+ }
+
+ if (d->path) {
+ if (d->is_root)
+ log_debug("Root directory %s removed.", d->path);
+ else
+ log_debug("Directory %s removed.", d->path);
+
+ free(d->path);
+ }
+
+ return mfree(d);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(Directory*, directory_free);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+ directories_by_path_hash_ops,
+ char,
+ path_hash_func,
+ path_compare,
+ Directory,
+ directory_free);
+
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
+ directories_by_wd_hash_ops,
+ void,
+ trivial_hash_func,
+ trivial_compare_func,
+ Directory,
+ directory_free);
+
+static int add_directory_impl(sd_journal *j, const char *path, bool is_root, Directory **ret) {
+ _cleanup_(directory_freep) Directory *m = NULL;
+ Directory *existing;
+ int r;
+
+ assert(j);
+ assert(path);
+ assert(ret);
+
+ existing = hashmap_get(j->directories_by_path, path);
+ if (existing) {
+ if (existing->is_root != is_root) {
+ /* Don't 'downgrade' from root directory */
+ *ret = NULL;
+ return 0;
+ }
+
+ *ret = existing;
+ return 1;
+ }
+
+ m = new(Directory, 1);
+ if (!m)
+ return -ENOMEM;
+
+ *m = (Directory) {
+ .journal = j,
+ .is_root = is_root,
+ .path = strdup(path),
+ .wd = -1,
+ };
+
+ if (!m->path)
+ return -ENOMEM;
+
+ r = hashmap_ensure_put(&j->directories_by_path, &directories_by_path_hash_ops, m->path, m);
+ if (r < 0)
+ return r;
+
+ j->current_invalidate_counter++;
+
+ if (is_root)
+ log_debug("Root directory %s added.", m->path);
+ else
+ log_debug("Directory %s added.", m->path);
+
+ *ret = TAKE_PTR(m);
+ return 1;
+}
+
static int add_directory(sd_journal *j, const char *prefix, const char *dirname);
static void directory_enumerate(sd_journal *j, Directory *m, DIR *d) {
@@ -1724,12 +1977,14 @@ static void directory_watch(sd_journal *j, Directory *m, int fd, uint32_t mask)
return;
}
- r = hashmap_put(j->directories_by_wd, INT_TO_PTR(m->wd), m);
- if (r == -EEXIST)
- log_debug_errno(r, "Directory '%s' already being watched under a different path, ignoring: %m", m->path);
+ r = hashmap_ensure_put(&j->directories_by_wd, &directories_by_wd_hash_ops, INT_TO_PTR(m->wd), m);
if (r < 0) {
- log_debug_errno(r, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m->path);
- (void) inotify_rm_watch(j->inotify_fd, m->wd);
+ if (r == -EEXIST)
+ log_debug_errno(r, "Directory '%s' already being watched under a different path, ignoring: %m", m->path);
+ else {
+ log_debug_errno(r, "Failed to add watch for journal directory '%s' to hashmap, ignoring: %m", m->path);
+ (void) inotify_rm_watch(j->inotify_fd, m->wd);
+ }
m->wd = -1;
}
}
@@ -1775,32 +2030,11 @@ static int add_directory(
goto fail;
}
- m = hashmap_get(j->directories_by_path, path);
- if (!m) {
- m = new(Directory, 1);
- if (!m) {
- r = -ENOMEM;
- goto fail;
- }
-
- *m = (Directory) {
- .is_root = false,
- .path = path,
- };
-
- if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
- free(m);
- r = -ENOMEM;
- goto fail;
- }
-
- path = NULL; /* avoid freeing in cleanup */
- j->current_invalidate_counter++;
-
- log_debug("Directory %s added.", m->path);
-
- } else if (m->is_root)
- return 0; /* Don't 'downgrade' from root directory */
+ r = add_directory_impl(j, path, /* is_root = */ false, &m);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
+ return 0;
m->last_seen_generation = j->generation;
@@ -1878,35 +2112,10 @@ static int add_root_directory(sd_journal *j, const char *p, bool missing_ok) {
rewinddir(d);
}
- m = hashmap_get(j->directories_by_path, p);
- if (!m) {
- m = new0(Directory, 1);
- if (!m) {
- r = -ENOMEM;
- goto fail;
- }
-
- m->is_root = true;
-
- m->path = strdup(p);
- if (!m->path) {
- free(m);
- r = -ENOMEM;
- goto fail;
- }
-
- if (hashmap_put(j->directories_by_path, m->path, m) < 0) {
- free(m->path);
- free(m);
- r = -ENOMEM;
- goto fail;
- }
-
- j->current_invalidate_counter++;
-
- log_debug("Root directory %s added.", m->path);
-
- } else if (!m->is_root)
+ r = add_directory_impl(j, p, /* is_root = */ true, &m);
+ if (r < 0)
+ goto fail;
+ if (r == 0)
return 0;
directory_watch(j, m, dirfd(d),
@@ -1928,27 +2137,6 @@ fail:
return r;
}
-static void remove_directory(sd_journal *j, Directory *d) {
- assert(j);
-
- if (d->wd > 0) {
- hashmap_remove(j->directories_by_wd, INT_TO_PTR(d->wd));
-
- if (j->inotify_fd >= 0)
- (void) inotify_rm_watch(j->inotify_fd, d->wd);
- }
-
- hashmap_remove(j->directories_by_path, d->path);
-
- if (d->is_root)
- log_debug("Root directory %s removed.", d->path);
- else
- log_debug("Directory %s removed.", d->path);
-
- free(d->path);
- free(d);
-}
-
static int add_search_paths(sd_journal *j) {
static const char search_paths[] =
@@ -2003,7 +2191,7 @@ static int allocate_inotify(sd_journal *j) {
return -errno;
}
- return hashmap_ensure_allocated(&j->directories_by_wd, NULL);
+ return 0;
}
static sd_journal *journal_new(int flags, const char *path, const char *namespace) {
@@ -2045,9 +2233,8 @@ static sd_journal *journal_new(int flags, const char *path, const char *namespac
return NULL;
j->files_cache = ordered_hashmap_iterated_cache_new(j->files);
- j->directories_by_path = hashmap_new(&path_hash_ops);
j->mmap = mmap_cache_new();
- if (!j->files_cache || !j->directories_by_path || !j->mmap)
+ if (!j->files_cache || !j->mmap)
return NULL;
return TAKE_PTR(j);
@@ -2059,7 +2246,8 @@ static sd_journal *journal_new(int flags, const char *path, const char *namespac
SD_JOURNAL_SYSTEM | \
SD_JOURNAL_CURRENT_USER | \
SD_JOURNAL_ALL_NAMESPACES | \
- SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE)
+ SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE | \
+ SD_JOURNAL_ASSUME_IMMUTABLE)
_public_ int sd_journal_open_namespace(sd_journal **ret, const char *namespace, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
@@ -2085,7 +2273,9 @@ _public_ int sd_journal_open(sd_journal **ret, int flags) {
}
#define OPEN_CONTAINER_ALLOWED_FLAGS \
- (SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_SYSTEM)
+ (SD_JOURNAL_LOCAL_ONLY | \
+ SD_JOURNAL_SYSTEM | \
+ SD_JOURNAL_ASSUME_IMMUTABLE)
_public_ int sd_journal_open_container(sd_journal **ret, const char *machine, int flags) {
_cleanup_free_ char *root = NULL, *class = NULL;
@@ -2129,7 +2319,9 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in
#define OPEN_DIRECTORY_ALLOWED_FLAGS \
(SD_JOURNAL_OS_ROOT | \
- SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
+ SD_JOURNAL_SYSTEM | \
+ SD_JOURNAL_CURRENT_USER | \
+ SD_JOURNAL_ASSUME_IMMUTABLE)
_public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
@@ -2154,12 +2346,15 @@ _public_ int sd_journal_open_directory(sd_journal **ret, const char *path, int f
return 0;
}
+#define OPEN_FILES_ALLOWED_FLAGS \
+ (SD_JOURNAL_ASSUME_IMMUTABLE)
+
_public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
int r;
assert_return(ret, -EINVAL);
- assert_return(flags == 0, -EINVAL);
+ assert_return((flags & ~OPEN_FILES_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, NULL, NULL);
if (!j)
@@ -2181,7 +2376,8 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
(SD_JOURNAL_OS_ROOT | \
SD_JOURNAL_SYSTEM | \
SD_JOURNAL_CURRENT_USER | \
- SD_JOURNAL_TAKE_DIRECTORY_FD)
+ SD_JOURNAL_TAKE_DIRECTORY_FD | \
+ SD_JOURNAL_ASSUME_IMMUTABLE)
_public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
@@ -2219,6 +2415,9 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
return 0;
}
+#define OPEN_FILES_FD_ALLOWED_FLAGS \
+ (SD_JOURNAL_ASSUME_IMMUTABLE)
+
_public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fds, int flags) {
JournalFile *f;
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
@@ -2226,7 +2425,7 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd
assert_return(ret, -EINVAL);
assert_return(n_fds > 0, -EBADF);
- assert_return(flags == 0, -EINVAL);
+ assert_return((flags & ~OPEN_FILES_FD_ALLOWED_FLAGS) == 0, -EINVAL);
j = journal_new(flags, NULL, NULL);
if (!j)
@@ -2270,27 +2469,16 @@ fail:
}
_public_ void sd_journal_close(sd_journal *j) {
- Directory *d;
- Prioq *p;
-
if (!j || journal_origin_changed(j))
return;
- while ((p = hashmap_first(j->newest_by_boot_id)))
- journal_file_unlink_newest_by_boot_id(j, prioq_peek(p));
- hashmap_free(j->newest_by_boot_id);
+ journal_clear_newest_by_boot_id(j);
sd_journal_flush_matches(j);
ordered_hashmap_free_with_destructor(j->files, journal_file_close);
iterated_cache_free(j->files_cache);
- while ((d = hashmap_first(j->directories_by_path)))
- remove_directory(j, d);
-
- while ((d = hashmap_first(j->directories_by_wd)))
- remove_directory(j, d);
-
hashmap_free(j->directories_by_path);
hashmap_free(j->directories_by_wd);
@@ -2306,6 +2494,8 @@ _public_ void sd_journal_close(sd_journal *j) {
hashmap_free_free(j->errors);
+ set_free(j->exclude_syslog_identifiers);
+
free(j->path);
free(j->prefix);
free(j->namespace);
@@ -2314,84 +2504,6 @@ _public_ void sd_journal_close(sd_journal *j) {
free(j);
}
-static void journal_file_unlink_newest_by_boot_id(sd_journal *j, JournalFile *f) {
- JournalFile *nf;
- Prioq *p;
-
- assert(j);
- assert(f);
-
- if (f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL) /* not linked currently, hence this is a NOP */
- return;
-
- assert_se(p = hashmap_get(j->newest_by_boot_id, &f->newest_boot_id));
- assert_se(prioq_remove(p, f, &f->newest_boot_id_prioq_idx) > 0);
-
- nf = prioq_peek(p);
- if (nf)
- /* There's still a member in the prioq? Then make sure the hashmap key now points to its
- * .newest_boot_id field (and not ours!). Not we only replace the memory of the key here, the
- * value of the key (and the data associated with it) remain the same. */
- assert_se(hashmap_replace(j->newest_by_boot_id, &nf->newest_boot_id, p) >= 0);
- else {
- assert_se(hashmap_remove(j->newest_by_boot_id, &f->newest_boot_id) == p);
- prioq_free(p);
- }
-
- f->newest_boot_id_prioq_idx = PRIOQ_IDX_NULL;
-}
-
-static int journal_file_newest_monotonic_compare(const void *a, const void *b) {
- const JournalFile *x = a, *y = b;
-
- return -CMP(x->newest_monotonic_usec, y->newest_monotonic_usec); /* Invert order, we want newest first! */
-}
-
-static int journal_file_reshuffle_newest_by_boot_id(sd_journal *j, JournalFile *f) {
- Prioq *p;
- int r;
-
- assert(j);
- assert(f);
-
- p = hashmap_get(j->newest_by_boot_id, &f->newest_boot_id);
- if (p) {
- /* There's already a priority queue for this boot ID */
-
- if (f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL) {
- r = prioq_put(p, f, &f->newest_boot_id_prioq_idx); /* Insert if we aren't in there yet */
- if (r < 0)
- return r;
- } else
- prioq_reshuffle(p, f, &f->newest_boot_id_prioq_idx); /* Reshuffle otherwise */
-
- } else {
- _cleanup_(prioq_freep) Prioq *q = NULL;
-
- /* No priority queue yet, then allocate one */
-
- assert(f->newest_boot_id_prioq_idx == PRIOQ_IDX_NULL); /* we can't be a member either */
-
- q = prioq_new(journal_file_newest_monotonic_compare);
- if (!q)
- return -ENOMEM;
-
- r = prioq_put(q, f, &f->newest_boot_id_prioq_idx);
- if (r < 0)
- return r;
-
- r = hashmap_ensure_put(&j->newest_by_boot_id, &id128_hash_ops, &f->newest_boot_id, q);
- if (r < 0) {
- f->newest_boot_id_prioq_idx = PRIOQ_IDX_NULL;
- return r;
- }
-
- TAKE_PTR(q);
- }
-
- return 0;
-}
-
static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
uint64_t offset, mo, rt;
sd_id128_t id;
@@ -2405,11 +2517,13 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
/* Tries to read the timestamp of the most recently written entry. */
- r = journal_file_fstat(f);
- if (r < 0)
- return r;
- if (f->newest_mtime == timespec_load(&f->last_stat.st_mtim))
- return 0; /* mtime didn't change since last time, don't bother */
+ if (FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE) && f->newest_entry_offset != 0)
+ return 0; /* We have already read the file, and we assume that the file is immutable. */
+
+ if (f->header->state == f->newest_state &&
+ f->header->state == STATE_ARCHIVED &&
+ f->newest_entry_offset != 0)
+ return 0; /* We have already read archived file. */
if (JOURNAL_HEADER_CONTAINS(f->header, tail_entry_offset)) {
offset = le64toh(READ_NOW(f->header->tail_entry_offset));
@@ -2420,6 +2534,8 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
}
if (offset == 0)
return -ENODATA; /* not a single object/entry, hence no tail timestamp */
+ if (offset == f->newest_entry_offset)
+ return 0; /* No new entry is added after we read last time. */
/* Move to the last object in the journal file, in the hope it is an entry (which it usually will
* be). If we lack the "tail_entry_offset" field in the header, we specify the type as OBJECT_UNUSED
@@ -2429,6 +2545,7 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
if (r < 0) {
log_debug_errno(r, "Failed to move to last object in journal file, ignoring: %m");
o = NULL;
+ offset = 0;
}
if (o && o->object.type == OBJECT_ENTRY) {
/* Yay, last object is an entry, let's use the data. */
@@ -2446,10 +2563,11 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
mo = le64toh(f->header->tail_entry_monotonic);
rt = le64toh(f->header->tail_entry_realtime);
id = f->header->tail_entry_boot_id;
+ offset = UINT64_MAX;
} else {
/* Otherwise let's find the last entry manually (this possibly means traversing the
* chain of entry arrays, till the end */
- r = journal_file_next_entry(f, 0, DIRECTION_UP, &o, NULL);
+ r = journal_file_next_entry(f, 0, DIRECTION_UP, &o, offset == 0 ? &offset : NULL);
if (r < 0)
return r;
if (r == 0)
@@ -2464,6 +2582,17 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
if (mo > rt) /* monotonic clock is further ahead than realtime? that's weird, refuse to use the data */
return -ENODATA;
+ if (offset == f->newest_entry_offset) {
+ /* Cached data and the current one should be equivalent. */
+ if (!sd_id128_equal(f->newest_machine_id, f->header->machine_id) ||
+ !sd_id128_equal(f->newest_boot_id, id) ||
+ f->newest_monotonic_usec != mo ||
+ f->newest_realtime_usec != rt)
+ return -EBADMSG;
+
+ return 0; /* No new entry is added after we read last time. */
+ }
+
if (!sd_id128_equal(f->newest_boot_id, id))
journal_file_unlink_newest_by_boot_id(j, f);
@@ -2471,13 +2600,14 @@ static int journal_file_read_tail_timestamp(sd_journal *j, JournalFile *f) {
f->newest_monotonic_usec = mo;
f->newest_realtime_usec = rt;
f->newest_machine_id = f->header->machine_id;
- f->newest_mtime = timespec_load(&f->last_stat.st_mtim);
+ f->newest_entry_offset = offset;
+ f->newest_state = f->header->state;
r = journal_file_reshuffle_newest_by_boot_id(j, f);
if (r < 0)
return r;
- return 0;
+ return 1; /* Updated. */
}
_public_ int sd_journal_get_realtime_usec(sd_journal *j, uint64_t *ret) {
@@ -2526,9 +2656,7 @@ _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id12
if (r < 0)
return r;
- if (ret_boot_id)
- *ret_boot_id = o->entry.boot_id;
- else {
+ if (!ret_boot_id) {
sd_id128_t id;
r = sd_id128_get_boot(&id);
@@ -2545,6 +2673,8 @@ _public_ int sd_journal_get_monotonic_usec(sd_journal *j, uint64_t *ret, sd_id12
if (ret)
*ret = t;
+ if (ret_boot_id)
+ *ret_boot_id = o->entry.boot_id;
return 0;
}
@@ -2748,6 +2878,7 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_origin_changed(j), -ECHILD);
+ assert_return(!FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE), -EUNATCH);
if (j->no_inotify)
return -EMEDIUMTYPE;
@@ -2774,6 +2905,7 @@ _public_ int sd_journal_get_events(sd_journal *j) {
assert_return(j, -EINVAL);
assert_return(!journal_origin_changed(j), -ECHILD);
+ assert_return(!FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE), -EUNATCH);
fd = sd_journal_get_fd(j);
if (fd < 0)
@@ -2787,6 +2919,7 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) {
assert_return(j, -EINVAL);
assert_return(!journal_origin_changed(j), -ECHILD);
+ assert_return(!FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE), -EUNATCH);
assert_return(timeout_usec, -EINVAL);
fd = sd_journal_get_fd(j);
@@ -2839,7 +2972,7 @@ static void process_q_overflow(sd_journal *j) {
continue;
log_debug("Directory '%s' hasn't been seen in this enumeration, removing.", f->path);
- remove_directory(j, m);
+ directory_free(m);
}
log_debug("Reiteration complete.");
@@ -2875,7 +3008,7 @@ static void process_inotify_event(sd_journal *j, const struct inotify_event *e)
/* Event for a subdirectory */
if (e->mask & (IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT))
- remove_directory(j, d);
+ directory_free(d);
} else if (d->is_root && (e->mask & IN_ISDIR) && e->len > 0 && id128_is_valid(e->name)) {
@@ -2914,6 +3047,8 @@ _public_ int sd_journal_process(sd_journal *j) {
if (j->inotify_fd < 0) /* We have no inotify fd yet? Then there's noting to process. */
return 0;
+ assert_return(!FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE), -EUNATCH);
+
j->last_process_usec = now(CLOCK_MONOTONIC);
j->last_invalidate_counter = j->current_invalidate_counter;
@@ -2942,6 +3077,7 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) {
assert_return(j, -EINVAL);
assert_return(!journal_origin_changed(j), -ECHILD);
+ assert_return(!FLAGS_SET(j->flags, SD_JOURNAL_ASSUME_IMMUTABLE), -EUNATCH);
if (j->inotify_fd < 0) {
JournalFile *f;
diff --git a/src/libsystemd/sd-journal/test-journal-append.c b/src/libsystemd/sd-journal/test-journal-append.c
index 24b98c8..b7e7c78 100644
--- a/src/libsystemd/sd-journal/test-journal-append.c
+++ b/src/libsystemd/sd-journal/test-journal-append.c
@@ -62,7 +62,7 @@ static int journal_corrupt_and_append(uint64_t start_offset, uint64_t step) {
log_debug("Opening journal %s/system.journal", tempdir);
r = journal_file_open(
- /* fd= */ -1,
+ /* fd= */ -EBADF,
"system.journal",
O_RDWR|O_CREAT,
JOURNAL_COMPRESS,
@@ -114,7 +114,7 @@ static int journal_corrupt_and_append(uint64_t start_offset, uint64_t step) {
* the corrupted journal */
mj = journal_file_offline_close(mj);
r = journal_file_open(
- /* fd= */ -1,
+ /* fd= */ -EBADF,
"system.journal",
O_RDWR|O_CREAT,
JOURNAL_COMPRESS,
diff --git a/src/libsystemd/sd-journal/test-journal-enum.c b/src/libsystemd/sd-journal/test-journal-enum.c
index 03fe8e2..d101fe7 100644
--- a/src/libsystemd/sd-journal/test-journal-enum.c
+++ b/src/libsystemd/sd-journal/test-journal-enum.c
@@ -15,10 +15,10 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
- assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY) >= 0);
+ assert_se(sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE) >= 0);
- assert_se(sd_journal_add_match(j, "_TRANSPORT=syslog", 0) >= 0);
- assert_se(sd_journal_add_match(j, "_UID=0", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "_TRANSPORT=syslog", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "_UID=0", SIZE_MAX) >= 0);
SD_JOURNAL_FOREACH_BACKWARDS(j) {
const void *d;
diff --git a/src/libsystemd/sd-journal/test-journal-flush.c b/src/libsystemd/sd-journal/test-journal-flush.c
index 3f07835..b06645a 100644
--- a/src/libsystemd/sd-journal/test-journal-flush.c
+++ b/src/libsystemd/sd-journal/test-journal-flush.c
@@ -7,6 +7,8 @@
#include "alloc-util.h"
#include "chattr-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
#include "journal-file-util.h"
#include "journal-internal.h"
#include "logs-show.h"
@@ -17,6 +19,83 @@
#include "tests.h"
#include "tmpfile-util.h"
+static int open_archive_file(sd_journal **ret) {
+ _cleanup_closedir_ DIR *d = NULL;
+ _cleanup_close_ int newest_fd = -EBADF;
+ unsigned long long newest_realtime = 0;
+ bool newest_is_system = false;
+ sd_id128_t machine_id;
+ const char *p;
+ int r;
+
+ r = sd_id128_get_machine(&machine_id);
+ if (r < 0)
+ return r;
+
+ p = strjoina("/var/log/journal/", SD_ID128_TO_STRING(machine_id), "/");
+
+ d = opendir(p);
+ if (!d)
+ return -errno;
+
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
+ unsigned long long realtime;
+ bool is_system;
+ size_t q;
+ int fd;
+
+ if (!dirent_is_file_with_suffix(de, ".journal"))
+ continue;
+
+ is_system = startswith(de->d_name, "system@");
+ if (newest_is_system && !is_system)
+ continue;
+
+ q = strlen(de->d_name);
+
+ if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
+ continue;
+
+ if (de->d_name[q-8-16-1] != '-' ||
+ de->d_name[q-8-16-1-16-1] != '-' ||
+ de->d_name[q-8-16-1-16-1-32-1] != '@')
+ continue;
+
+ if (sscanf(de->d_name + q-8-16, "%16llx.journal", &realtime) != 1)
+ continue;
+
+ if (newest_realtime >= realtime)
+ continue;
+
+ fd = openat(dirfd(d), de->d_name, O_CLOEXEC | O_NONBLOCK | O_RDONLY);
+ if (fd < 0) {
+ log_info_errno(errno, "Failed to open /var/log/journal/%s, ignoring: %m", de->d_name);
+ continue;
+ }
+
+ close_and_replace(newest_fd, fd);
+ newest_realtime = realtime;
+ newest_is_system = is_system;
+ }
+
+ if (newest_fd < 0)
+ return log_info_errno(SYNTHETIC_ERRNO(ENOENT), "No archive journal found.");
+
+ r = sd_journal_open_files_fd(ret, &newest_fd, 1, SD_JOURNAL_ASSUME_IMMUTABLE);
+
+ _cleanup_free_ char *path = NULL;
+ (void) fd_get_path(newest_fd, &path);
+
+ if (r < 0)
+ log_info_errno(r, "Failed to open %s, ignoring: %m", strna(path));
+ else {
+ log_info("Opened %s.", strna(path));
+ TAKE_FD(newest_fd);
+ }
+
+ return r;
+}
+
static void test_journal_flush_one(int argc, char *argv[]) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
_cleanup_free_ char *fn = NULL;
@@ -32,13 +111,16 @@ static void test_journal_flush_one(int argc, char *argv[]) {
assert_se(fn = path_join(dn, "test.journal"));
- r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0, 0644, 0, NULL, m, NULL, &new_journal);
+ r = journal_file_open(-EBADF, fn, O_CREAT|O_RDWR, 0, 0644, 0, NULL, m, NULL, &new_journal);
assert_se(r >= 0);
if (argc > 1)
- r = sd_journal_open_files(&j, (const char **) strv_skip(argv, 1), 0);
- else
- r = sd_journal_open(&j, 0);
+ r = sd_journal_open_files(&j, (const char **) strv_skip(argv, 1), SD_JOURNAL_ASSUME_IMMUTABLE);
+ else {
+ r = open_archive_file(&j);
+ if (r < 0)
+ r = sd_journal_open(&j, SD_JOURNAL_ASSUME_IMMUTABLE);
+ }
assert_se(r == 0);
sd_journal_set_data_threshold(j, 0);
@@ -75,7 +157,7 @@ static void test_journal_flush_one(int argc, char *argv[]) {
/* Open the new journal before archiving and offlining the file. */
sd_journal_close(j);
- assert_se(sd_journal_open_directory(&j, dn, 0) >= 0);
+ assert_se(sd_journal_open_directory(&j, dn, SD_JOURNAL_ASSUME_IMMUTABLE) >= 0);
/* Read the online journal. */
assert_se(sd_journal_seek_tail(j) >= 0);
diff --git a/src/libsystemd/sd-journal/test-journal-init.c b/src/libsystemd/sd-journal/test-journal-init.c
index c8a1977..ef66efd 100644
--- a/src/libsystemd/sd-journal/test-journal-init.c
+++ b/src/libsystemd/sd-journal/test-journal-init.c
@@ -31,12 +31,12 @@ int main(int argc, char *argv[]) {
(void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
for (i = 0; i < I; i++) {
- r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
+ r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY | SD_JOURNAL_ASSUME_IMMUTABLE);
assert_se(r == 0);
sd_journal_close(j);
- r = sd_journal_open_directory(&j, t, 0);
+ r = sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE);
assert_se(r == 0);
assert_se(sd_journal_seek_head(j) == 0);
@@ -45,8 +45,8 @@ int main(int argc, char *argv[]) {
r = safe_fork("(journal-fork-test)", FORK_WAIT|FORK_LOG, NULL);
if (r == 0) {
assert_se(j);
- assert_se(sd_journal_get_realtime_usec(j, NULL) == -ECHILD);
- assert_se(sd_journal_seek_tail(j) == -ECHILD);
+ ASSERT_RETURN_EXPECTED_SE(sd_journal_get_realtime_usec(j, NULL) == -ECHILD);
+ ASSERT_RETURN_EXPECTED_SE(sd_journal_seek_tail(j) == -ECHILD);
assert_se(j->current_location.type == LOCATION_HEAD);
sd_journal_close(j);
_exit(EXIT_SUCCESS);
@@ -57,8 +57,7 @@ int main(int argc, char *argv[]) {
sd_journal_close(j);
j = NULL;
- r = sd_journal_open_directory(&j, t, SD_JOURNAL_LOCAL_ONLY);
- assert_se(r == -EINVAL);
+ ASSERT_RETURN_EXPECTED(assert_se(sd_journal_open_directory(&j, t, SD_JOURNAL_LOCAL_ONLY) == -EINVAL));
assert_se(j == NULL);
}
diff --git a/src/libsystemd/sd-journal/test-journal-interleaving.c b/src/libsystemd/sd-journal/test-journal-interleaving.c
index 8aeef8f..d98b3ce 100644
--- a/src/libsystemd/sd-journal/test-journal-interleaving.c
+++ b/src/libsystemd/sd-journal/test-journal-interleaving.c
@@ -43,7 +43,7 @@ static JournalFile *test_open_internal(const char *name, JournalFileFlags flags)
m = mmap_cache_new();
assert_se(m != NULL);
- assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f));
+ assert_ret(journal_file_open(-EBADF, name, O_RDWR|O_CREAT, flags, 0644, UINT64_MAX, NULL, m, NULL, &f));
return f;
}
@@ -74,9 +74,9 @@ static void test_done(const char *t) {
}
static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint64_t *seqnum, uint64_t *ret_offset) {
- _cleanup_free_ char *p = NULL, *q = NULL;
+ _cleanup_free_ char *p = NULL, *q = NULL, *s = NULL;
dual_timestamp ts;
- struct iovec iovec[2];
+ struct iovec iovec[3];
size_t n_iov = 0;
dual_timestamp_now(&ts);
@@ -92,6 +92,9 @@ static void append_number(JournalFile *f, int n, const sd_id128_t *boot_id, uint
assert_se(asprintf(&p, "NUMBER=%d", n) >= 0);
iovec[n_iov++] = IOVEC_MAKE_STRING(p);
+ assert_se(s = strjoin("LESS_THAN_FIVE=%d", yes_no(n < 5)));
+ iovec[n_iov++] = IOVEC_MAKE_STRING(s);
+
if (boot_id) {
assert_se(q = strjoin("_BOOT_ID=", SD_ID128_TO_STRING(*boot_id)));
iovec[n_iov++] = IOVEC_MAKE_STRING(q);
@@ -250,6 +253,37 @@ static void mkdtemp_chdir_chattr(char *path) {
(void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
}
+static void test_cursor(sd_journal *j) {
+ _cleanup_strv_free_ char **cursors = NULL;
+ int r;
+
+ assert_se(sd_journal_seek_head(j) >= 0);
+
+ for (;;) {
+ r = sd_journal_next(j);
+ assert_se(r >= 0);
+ if (r == 0)
+ break;
+
+ _cleanup_free_ char *cursor = NULL;
+ assert_se(sd_journal_get_cursor(j, &cursor) >= 0);
+ assert_se(sd_journal_test_cursor(j, cursor) > 0);
+ assert_se(strv_consume(&cursors, TAKE_PTR(cursor)) >= 0);
+ }
+
+ STRV_FOREACH(c, cursors) {
+ assert_se(sd_journal_seek_cursor(j, *c) >= 0);
+ assert_se(sd_journal_next(j) >= 0);
+ assert_se(sd_journal_test_cursor(j, *c) > 0);
+ }
+
+ assert_se(sd_journal_seek_head(j) >= 0);
+ STRV_FOREACH(c, cursors) {
+ assert_se(sd_journal_next(j) >= 0);
+ assert_se(sd_journal_test_cursor(j, *c) > 0);
+ }
+}
+
static void test_skip_one(void (*setup)(void)) {
char t[] = "/var/tmp/journal-skip-XXXXXX";
sd_journal *j;
@@ -260,14 +294,14 @@ static void test_skip_one(void (*setup)(void)) {
setup();
/* Seek to head, iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
test_check_numbers_down(j, 9);
sd_journal_close(j);
/* Seek to head, iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
assert_se(sd_journal_previous(j) == 0); /* no-op */
@@ -275,7 +309,7 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to head twice, iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
assert_ret(sd_journal_seek_head(j));
@@ -284,7 +318,7 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to head, move to previous, then iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_previous(j) == 0); /* no-op */
assert_se(sd_journal_next(j) == 1); /* pointing to the first entry */
@@ -292,7 +326,7 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to head, walk several steps, then iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_previous(j) == 0); /* no-op */
assert_se(sd_journal_previous(j) == 0); /* no-op */
@@ -304,14 +338,14 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to tail, iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
test_check_numbers_up(j, 9);
sd_journal_close(j);
/* Seek to tail twice, iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
assert_ret(sd_journal_seek_tail(j));
@@ -320,7 +354,7 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to tail, move to next, then iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_next(j) == 0); /* no-op */
assert_se(sd_journal_previous(j) == 1); /* pointing to the last entry */
@@ -328,7 +362,7 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to tail, walk several steps, then iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_next(j) == 0); /* no-op */
assert_se(sd_journal_next(j) == 0); /* no-op */
@@ -340,14 +374,14 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to tail, skip to head, iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_previous_skip(j, 9) == 9); /* pointing to the first entry. */
test_check_numbers_down(j, 9);
sd_journal_close(j);
/* Seek to tail, skip to head in a more complex way, then iterate down. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_tail(j));
assert_se(sd_journal_next(j) == 0);
assert_se(sd_journal_previous_skip(j, 4) == 4);
@@ -366,14 +400,14 @@ static void test_skip_one(void (*setup)(void)) {
sd_journal_close(j);
/* Seek to head, skip to tail, iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_next_skip(j, 9) == 9);
test_check_numbers_up(j, 9);
sd_journal_close(j);
/* Seek to head, skip to tail in a more complex way, then iterate up. */
- assert_ret(sd_journal_open_directory(&j, t, 0));
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
assert_ret(sd_journal_seek_head(j));
assert_se(sd_journal_previous(j) == 0);
assert_se(sd_journal_next_skip(j, 4) == 4);
@@ -391,6 +425,30 @@ static void test_skip_one(void (*setup)(void)) {
test_check_numbers_up(j, 9);
sd_journal_close(j);
+ /* For issue #31516. */
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
+ test_cursor(j);
+ sd_journal_flush_matches(j);
+ assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+ test_cursor(j);
+ sd_journal_flush_matches(j);
+ assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=no", SIZE_MAX) >= 0);
+ test_cursor(j);
+ sd_journal_flush_matches(j);
+ assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=hoge", SIZE_MAX) >= 0);
+ test_cursor(j);
+ sd_journal_flush_matches(j);
+ assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0);
+ test_cursor(j);
+ sd_journal_flush_matches(j);
+ assert_se(sd_journal_add_match(j, "LESS_THAN_FIVE=yes", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=3", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=4", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=5", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=6", SIZE_MAX) >= 0);
+ test_cursor(j);
+
test_done(t);
}
@@ -401,7 +459,7 @@ TEST(skip) {
static void test_boot_id_one(void (*setup)(void), size_t n_boots_expected) {
char t[] = "/var/tmp/journal-boot-id-XXXXXX";
- sd_journal *j;
+ _cleanup_(sd_journal_closep) sd_journal *j = NULL;
_cleanup_free_ BootId *boots = NULL;
size_t n_boots;
@@ -409,28 +467,59 @@ static void test_boot_id_one(void (*setup)(void), size_t n_boots_expected) {
setup();
- assert_ret(sd_journal_open_directory(&j, t, 0));
- assert_se(journal_get_boots(j, &boots, &n_boots) >= 0);
+ assert_ret(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE));
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ false, /* max_ids = */ SIZE_MAX,
+ &boots, &n_boots) >= 0);
assert_se(boots);
assert_se(n_boots == n_boots_expected);
- sd_journal_close(j);
- FOREACH_ARRAY(b, boots, n_boots) {
- assert_ret(sd_journal_open_directory(&j, t, 0));
- assert_se(journal_find_boot_by_id(j, b->id) == 1);
- sd_journal_close(j);
+ for (size_t i = 0; i < n_boots; i++) {
+ sd_id128_t id;
+
+ /* positive offset */
+ assert_se(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1), &id) == 1);
+ assert_se(sd_id128_equal(id, boots[i].id));
+
+ /* negative offset */
+ assert_se(journal_find_boot(j, SD_ID128_NULL, (int) (i + 1) - (int) n_boots, &id) == 1);
+ assert_se(sd_id128_equal(id, boots[i].id));
+
+ for (size_t k = 0; k < n_boots; k++) {
+ int offset = (int) k - (int) i;
+
+ /* relative offset */
+ assert_se(journal_find_boot(j, boots[i].id, offset, &id) == 1);
+ assert_se(sd_id128_equal(id, boots[k].id));
+ }
}
- for (int i = - (int) n_boots + 1; i <= (int) n_boots; i++) {
- sd_id128_t id;
+ for (size_t i = 0; i <= n_boots_expected + 1; i++) {
+ _cleanup_free_ BootId *boots_limited = NULL;
+ size_t n_boots_limited;
+
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ false, /* max_ids = */ i,
+ &boots_limited, &n_boots_limited) >= 0);
+ assert_se(boots_limited || i == 0);
+ assert_se(n_boots_limited == MIN(i, n_boots_expected));
+ assert_se(memcmp_safe(boots, boots_limited, n_boots_limited * sizeof(BootId)) == 0);
+ }
- assert_ret(sd_journal_open_directory(&j, t, 0));
- assert_se(journal_find_boot_by_offset(j, i, &id) == 1);
- if (i <= 0)
- assert_se(sd_id128_equal(id, boots[n_boots + i - 1].id));
- else
- assert_se(sd_id128_equal(id, boots[i - 1].id));
- sd_journal_close(j);
+ for (size_t i = 0; i <= n_boots_expected + 1; i++) {
+ _cleanup_free_ BootId *boots_limited = NULL;
+ size_t n_boots_limited;
+
+ assert_se(journal_get_boots(
+ j,
+ /* advance_older = */ true, /* max_ids = */ i,
+ &boots_limited, &n_boots_limited) >= 0);
+ assert_se(boots_limited || i == 0);
+ assert_se(n_boots_limited == MIN(i, n_boots_expected));
+ for (size_t k = 0; k < n_boots_limited; k++)
+ assert_se(memcmp(&boots[n_boots - k - 1], &boots_limited[k], sizeof(BootId)) == 0);
}
test_done(t);
@@ -453,7 +542,7 @@ static void test_sequence_numbers_one(void) {
mkdtemp_chdir_chattr(t);
- assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
+ assert_se(journal_file_open(-EBADF, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
UINT64_MAX, NULL, m, NULL, &one) == 0);
append_number(one, 1, NULL, &seqnum, NULL);
@@ -470,7 +559,7 @@ static void test_sequence_numbers_one(void) {
memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t));
- assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
+ assert_se(journal_file_open(-EBADF, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
UINT64_MAX, NULL, m, one, &two) == 0);
assert_se(two->header->state == STATE_ONLINE);
@@ -502,12 +591,12 @@ static void test_sequence_numbers_one(void) {
test_close(one);
/* If the machine-id is not initialized, the header file verification
- * (which happens when re-opening a journal file) will fail. */
+ * (which happens when reopening a journal file) will fail. */
if (sd_id128_get_machine(NULL) >= 0) {
/* restart server */
seqnum = 0;
- assert_se(journal_file_open(-1, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
+ assert_se(journal_file_open(-EBADF, "two.journal", O_RDWR, JOURNAL_COMPRESS, 0,
UINT64_MAX, NULL, m, NULL, &two) == 0);
assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id));
@@ -567,7 +656,41 @@ static int expected_result(uint64_t needle, const uint64_t *candidates, const ui
}
}
-static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offset, size_t n) {
+static int expected_result_next(uint64_t needle, const uint64_t *candidates, const uint64_t *offset, size_t n, direction_t direction, uint64_t *ret) {
+ switch (direction) {
+ case DIRECTION_DOWN:
+ for (size_t i = 0; i < n; i++)
+ if (needle < offset[i]) {
+ *ret = candidates[i];
+ return candidates[i] > 0;
+ }
+ *ret = 0;
+ return 0;
+
+ case DIRECTION_UP:
+ for (size_t i = 0; i < n; i++)
+ if (needle <= offset[i]) {
+ n = i;
+ break;
+ }
+
+ for (; n > 0 && candidates[n - 1] == 0; n--)
+ ;
+
+ if (n == 0) {
+ *ret = 0;
+ return 0;
+ }
+
+ *ret = candidates[n - 1];
+ return candidates[n - 1] > 0;
+
+ default:
+ assert_not_reached();
+ }
+}
+
+static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offset_candidates, const uint64_t *offset, size_t n) {
uint64_t p, q;
int r, e;
@@ -664,12 +787,81 @@ static void verify(JournalFile *f, const uint64_t *seqnum, const uint64_t *offse
assert_se(r == e);
assert_se(p == q);
}
+
+ /* by journal_file_next_entry() */
+ for (size_t i = 0; i < n; i++) {
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] - 2, DIRECTION_DOWN, NULL, &p);
+ e = expected_result_next(offset[i] - 2, offset_candidates, offset, n, DIRECTION_DOWN, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] - 1, DIRECTION_DOWN, NULL, &p);
+ e = expected_result_next(offset[i] - 1, offset_candidates, offset, n, DIRECTION_DOWN, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i], DIRECTION_DOWN, NULL, &p);
+ e = expected_result_next(offset[i], offset_candidates, offset, n, DIRECTION_DOWN, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] + 1, DIRECTION_DOWN, NULL, &p);
+ e = expected_result_next(offset[i] + 1, offset_candidates, offset, n, DIRECTION_DOWN, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] - 1, DIRECTION_UP, NULL, &p);
+ e = expected_result_next(offset[i] - 1, offset_candidates, offset, n, DIRECTION_UP, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i], DIRECTION_UP, NULL, &p);
+ e = expected_result_next(offset[i], offset_candidates, offset, n, DIRECTION_UP, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] + 1, DIRECTION_UP, NULL, &p);
+ e = expected_result_next(offset[i] + 1, offset_candidates, offset, n, DIRECTION_UP, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+
+ p = 0;
+ r = journal_file_next_entry(f, offset[i] + 2, DIRECTION_UP, NULL, &p);
+ e = expected_result_next(offset[i] + 2, offset_candidates, offset, n, DIRECTION_UP, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+ }
+ for (size_t trial = 0; trial < 3 * n; trial++) {
+ uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
+
+ p = 0;
+ r = journal_file_next_entry(f, i, DIRECTION_DOWN, NULL, &p);
+ e = expected_result_next(i, offset_candidates, offset, n, DIRECTION_DOWN, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+ }
+ for (size_t trial = 0; trial < 3 * n; trial++) {
+ uint64_t i = offset[0] - 1 + random_u64_range(offset[n-1] - offset[0] + 2);
+
+ p = 0;
+ r = journal_file_next_entry(f, i, DIRECTION_UP, NULL, &p);
+ e = expected_result_next(i, offset_candidates, offset, n, DIRECTION_UP, &q);
+ assert_se(e == 0 ? r <= 0 : r > 0);
+ assert_se(p == q);
+ }
}
static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
_cleanup_(mmap_cache_unrefp) MMapCache *m = NULL;
char t[] = "/var/tmp/journal-seq-XXXXXX";
- _cleanup_free_ uint64_t *seqnum = NULL, *offset = NULL;
+ _cleanup_free_ uint64_t *seqnum = NULL, *offset = NULL, *offset_candidates = NULL;
JournalFile *f;
log_info("/* %s(%zu, %zu) */", __func__, n, num_corrupted);
@@ -678,7 +870,7 @@ static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
mkdtemp_chdir_chattr(t);
- assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
+ assert_se(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0644,
UINT64_MAX, NULL, m, NULL, &f) == 0);
assert_se(seqnum = new0(uint64_t, n));
@@ -695,7 +887,9 @@ static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
}
}
- verify(f, seqnum, offset, n);
+ assert_se(offset_candidates = newdup(uint64_t, offset, n));
+
+ verify(f, seqnum, offset_candidates, offset, n);
/* Reset chain cache. */
assert_se(journal_file_move_to_entry_by_offset(f, offset[0], DIRECTION_DOWN, NULL, NULL) > 0);
@@ -708,9 +902,10 @@ static void test_generic_array_bisect_one(size_t n, size_t num_corrupted) {
assert_se(o);
o->entry.seqnum = 0;
seqnum[i] = 0;
+ offset_candidates[i] = 0;
}
- verify(f, seqnum, offset, n);
+ verify(f, seqnum, offset_candidates, offset, n);
test_close(f);
test_done(t);
diff --git a/src/libsystemd/sd-journal/test-journal-match.c b/src/libsystemd/sd-journal/test-journal-match.c
index 571a88c..c2c345f 100644
--- a/src/libsystemd/sd-journal/test-journal-match.c
+++ b/src/libsystemd/sd-journal/test-journal-match.c
@@ -16,40 +16,40 @@ int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
- assert_se(sd_journal_open(&j, 0) >= 0);
+ assert_se(sd_journal_open(&j, SD_JOURNAL_ASSUME_IMMUTABLE) >= 0);
- assert_se(sd_journal_add_match(j, "foobar", 0) < 0);
- assert_se(sd_journal_add_match(j, "foobar=waldo", 0) < 0);
- assert_se(sd_journal_add_match(j, "", 0) < 0);
- assert_se(sd_journal_add_match(j, "=", 0) < 0);
- assert_se(sd_journal_add_match(j, "=xxxxx", 0) < 0);
+ assert_se(sd_journal_add_match(j, "foobar", SIZE_MAX) < 0);
+ assert_se(sd_journal_add_match(j, "foobar=waldo", SIZE_MAX) < 0);
+ assert_se(sd_journal_add_match(j, "", SIZE_MAX) < 0);
+ assert_se(sd_journal_add_match(j, "=", SIZE_MAX) < 0);
+ assert_se(sd_journal_add_match(j, "=xxxxx", SIZE_MAX) < 0);
assert_se(sd_journal_add_match(j, (uint8_t[4]){'A', '=', '\1', '\2'}, 4) >= 0);
assert_se(sd_journal_add_match(j, (uint8_t[5]){'B', '=', 'C', '\0', 'D'}, 5) >= 0);
- assert_se(sd_journal_add_match(j, "HALLO=WALDO", 0) >= 0);
- assert_se(sd_journal_add_match(j, "QUUX=mmmm", 0) >= 0);
- assert_se(sd_journal_add_match(j, "QUUX=xxxxx", 0) >= 0);
- assert_se(sd_journal_add_match(j, "HALLO=", 0) >= 0);
- assert_se(sd_journal_add_match(j, "QUUX=xxxxx", 0) >= 0);
- assert_se(sd_journal_add_match(j, "QUUX=yyyyy", 0) >= 0);
- assert_se(sd_journal_add_match(j, "PIFF=paff", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "HALLO=WALDO", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "QUUX=mmmm", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "QUUX=xxxxx", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "HALLO=", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "QUUX=xxxxx", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "QUUX=yyyyy", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "PIFF=paff", SIZE_MAX) >= 0);
assert_se(sd_journal_add_disjunction(j) >= 0);
- assert_se(sd_journal_add_match(j, "ONE=one", 0) >= 0);
- assert_se(sd_journal_add_match(j, "ONE=two", 0) >= 0);
- assert_se(sd_journal_add_match(j, "TWO=two", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "ONE=one", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "ONE=two", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "TWO=two", SIZE_MAX) >= 0);
assert_se(sd_journal_add_conjunction(j) >= 0);
- assert_se(sd_journal_add_match(j, "L4_1=yes", 0) >= 0);
- assert_se(sd_journal_add_match(j, "L4_1=ok", 0) >= 0);
- assert_se(sd_journal_add_match(j, "L4_2=yes", 0) >= 0);
- assert_se(sd_journal_add_match(j, "L4_2=ok", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "L4_1=yes", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "L4_1=ok", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "L4_2=yes", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "L4_2=ok", SIZE_MAX) >= 0);
assert_se(sd_journal_add_disjunction(j) >= 0);
- assert_se(sd_journal_add_match(j, "L3=yes", 0) >= 0);
- assert_se(sd_journal_add_match(j, "L3=ok", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "L3=yes", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "L3=ok", SIZE_MAX) >= 0);
assert_se(t = journal_make_match_string(j));
diff --git a/src/libsystemd/sd-journal/test-journal-stream.c b/src/libsystemd/sd-journal/test-journal-stream.c
index 3a370ef..00c0435 100644
--- a/src/libsystemd/sd-journal/test-journal-stream.c
+++ b/src/libsystemd/sd-journal/test-journal-stream.c
@@ -76,9 +76,9 @@ static void run_test(void) {
assert_se(chdir(t) >= 0);
(void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
- assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &one) == 0);
- assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &two) == 0);
- assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &three) == 0);
+ assert_se(journal_file_open(-EBADF, "one.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &one) == 0);
+ assert_se(journal_file_open(-EBADF, "two.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &two) == 0);
+ assert_se(journal_file_open(-EBADF, "three.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &three) == 0);
for (i = 0; i < N_ENTRIES; i++) {
char *p, *q;
@@ -119,9 +119,9 @@ static void run_test(void) {
(void) journal_file_offline_close(two);
(void) journal_file_offline_close(three);
- assert_se(sd_journal_open_directory(&j, t, 0) >= 0);
+ assert_se(sd_journal_open_directory(&j, t, SD_JOURNAL_ASSUME_IMMUTABLE) >= 0);
- assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "MAGIC=quux", SIZE_MAX) >= 0);
SD_JOURNAL_FOREACH_BACKWARDS(j) {
_cleanup_free_ char *c;
@@ -147,7 +147,7 @@ static void run_test(void) {
verify_contents(j, 1);
printf("NEXT TEST\n");
- assert_se(sd_journal_add_match(j, "MAGIC=quux", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "MAGIC=quux", SIZE_MAX) >= 0);
assert_se(z = journal_make_match_string(j));
printf("resulting match expression is: %s\n", z);
@@ -157,10 +157,10 @@ static void run_test(void) {
printf("NEXT TEST\n");
sd_journal_flush_matches(j);
- assert_se(sd_journal_add_match(j, "MAGIC=waldo", 0) >= 0);
- assert_se(sd_journal_add_match(j, "NUMBER=10", 0) >= 0);
- assert_se(sd_journal_add_match(j, "NUMBER=11", 0) >= 0);
- assert_se(sd_journal_add_match(j, "NUMBER=12", 0) >= 0);
+ assert_se(sd_journal_add_match(j, "MAGIC=waldo", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=10", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=11", SIZE_MAX) >= 0);
+ assert_se(sd_journal_add_match(j, "NUMBER=12", SIZE_MAX) >= 0);
assert_se(z = journal_make_match_string(j));
printf("resulting match expression is: %s\n", z);
diff --git a/src/libsystemd/sd-journal/test-journal-verify.c b/src/libsystemd/sd-journal/test-journal-verify.c
index edce440..396ebe1 100644
--- a/src/libsystemd/sd-journal/test-journal-verify.c
+++ b/src/libsystemd/sd-journal/test-journal-verify.c
@@ -47,7 +47,7 @@ static int raw_verify(const char *fn, const char *verification_key) {
assert_se(m != NULL);
r = journal_file_open(
- /* fd= */ -1,
+ /* fd= */ -EBADF,
fn,
O_RDONLY,
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
@@ -92,7 +92,7 @@ static int run_test(const char *verification_key, ssize_t max_iterations) {
log_info("Generating a test journal");
assert_se(journal_file_open(
- /* fd= */ -1,
+ /* fd= */ -EBADF,
"test.journal",
O_RDWR|O_CREAT,
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
@@ -128,7 +128,7 @@ static int run_test(const char *verification_key, ssize_t max_iterations) {
log_info("Verifying with key: %s", strna(verification_key));
assert_se(journal_file_open(
- /* fd= */ -1,
+ /* fd= */ -EBADF,
"test.journal",
O_RDONLY,
JOURNAL_COMPRESS|(verification_key ? JOURNAL_SEAL : 0),
diff --git a/src/libsystemd/sd-journal/test-journal.c b/src/libsystemd/sd-journal/test-journal.c
index 96f2b67..19a6d2d 100644
--- a/src/libsystemd/sd-journal/test-journal.c
+++ b/src/libsystemd/sd-journal/test-journal.c
@@ -39,7 +39,7 @@ static void test_non_empty_one(void) {
mkdtemp_chdir_chattr(t);
- assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f) == 0);
+ assert_se(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f) == 0);
assert_se(dual_timestamp_now(&ts));
assert_se(sd_id128_randomize(&fake_boot_id) == 0);
@@ -136,10 +136,10 @@ static void test_empty_one(void) {
mkdtemp_chdir_chattr(t);
- assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0, 0666, UINT64_MAX, NULL, m, NULL, &f1) == 0);
- assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &f2) == 0);
- assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f3) == 0);
- assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f4) == 0);
+ assert_se(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, 0, 0666, UINT64_MAX, NULL, m, NULL, &f1) == 0);
+ assert_se(journal_file_open(-EBADF, "test-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS, 0666, UINT64_MAX, NULL, m, NULL, &f2) == 0);
+ assert_se(journal_file_open(-EBADF, "test-seal.journal", O_RDWR|O_CREAT, JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f3) == 0);
+ assert_se(journal_file_open(-EBADF, "test-seal-compress.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, UINT64_MAX, NULL, m, NULL, &f4) == 0);
journal_file_print_header(f1);
puts("");
@@ -194,7 +194,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
mkdtemp_chdir_chattr(t);
- assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, compress_threshold, NULL, m, NULL, &f) == 0);
+ assert_se(journal_file_open(-EBADF, "test.journal", O_RDWR|O_CREAT, JOURNAL_COMPRESS|JOURNAL_SEAL, 0666, compress_threshold, NULL, m, NULL, &f) == 0);
dual_timestamp_now(&ts);
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index f9e86c6..4d91ba9 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -579,10 +579,7 @@ _public_ int sd_uid_is_on_seat(uid_t uid, int require_active, const char *seat)
if (isempty(content))
return 0;
- char t[DECIMAL_STR_MAX(uid_t)];
- xsprintf(t, UID_FMT, uid);
-
- return string_contains_word(content, NULL, t);
+ return string_contains_word(content, NULL, FORMAT_UID(uid));
}
static int uid_get_array(uid_t uid, const char *variable, char ***array) {
@@ -1275,7 +1272,7 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) {
_public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) {
if (m)
- (void) close_nointr(MONITOR_TO_FD(m));
+ (void) close(MONITOR_TO_FD(m));
return NULL;
}
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 819f86f..66e4274 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -1,6 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <poll.h>
+#if HAVE_PIDFD_OPEN
+#include <sys/pidfd.h>
+#endif
#include "sd-login.h"
@@ -10,6 +13,7 @@
#include "format-util.h"
#include "log.h"
#include "missing_syscall.h"
+#include "mountpoint-util.h"
#include "process-util.h"
#include "string-util.h"
#include "strv.h"
@@ -103,7 +107,7 @@ TEST(login) {
assert_se(IN_SET(r, 0, -ENOMEDIUM));
}
- r = sd_uid_get_display(u2, &display_session);
+ r = ASSERT_RETURN_IS_CRITICAL(uid_is_valid(u2), sd_uid_get_display(u2, &display_session));
log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));
if (u2 == UID_INVALID)
assert_se(r == -EINVAL);
@@ -115,7 +119,7 @@ TEST(login) {
sd_peer_get_session(pair[1], &qq);
assert_se(streq_ptr(pp, qq));
- r = sd_uid_get_sessions(u2, false, &sessions);
+ r = ASSERT_RETURN_IS_CRITICAL(uid_is_valid(u2), sd_uid_get_sessions(u2, false, &sessions));
assert_se(t = strv_join(sessions, " "));
log_info("sd_uid_get_sessions("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
if (u2 == UID_INVALID)
@@ -127,9 +131,9 @@ TEST(login) {
sessions = strv_free(sessions);
free(t);
- assert_se(r == sd_uid_get_sessions(u2, false, NULL));
+ assert_se(r == ASSERT_RETURN_IS_CRITICAL(uid_is_valid(u2), sd_uid_get_sessions(u2, false, NULL)));
- r = sd_uid_get_seats(u2, false, &seats);
+ r = ASSERT_RETURN_IS_CRITICAL(uid_is_valid(u2), sd_uid_get_seats(u2, false, &seats));
assert_se(t = strv_join(seats, " "));
log_info("sd_uid_get_seats("UID_FMT", …) → %s \"%s\"", u2, e(r), t);
if (u2 == UID_INVALID)
@@ -141,7 +145,7 @@ TEST(login) {
seats = strv_free(seats);
free(t);
- assert_se(r == sd_uid_get_seats(u2, false, NULL));
+ assert_se(r == ASSERT_RETURN_IS_CRITICAL(uid_is_valid(u2), sd_uid_get_seats(u2, false, NULL)));
if (session) {
r = sd_session_is_active(session);
@@ -327,6 +331,9 @@ TEST(monitor) {
}
static int intro(void) {
+ if (IN_SET(cg_unified(), -ENOENT, -ENOMEDIUM))
+ return log_tests_skipped("cgroupfs is not mounted");
+
log_info("/* Information printed is from the live system */");
return EXIT_SUCCESS;
}
diff --git a/src/libsystemd/sd-netlink/netlink-message-rtnl.c b/src/libsystemd/sd-netlink/netlink-message-rtnl.c
index 008e802..fb11c7e 100644
--- a/src/libsystemd/sd-netlink/netlink-message-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-message-rtnl.c
@@ -56,6 +56,10 @@ static bool rtnl_message_type_is_mdb(uint16_t type) {
return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB);
}
+static bool rtnl_message_type_is_nsid(uint16_t type) {
+ return IN_SET(type, RTM_NEWNSID, RTM_DELNSID, RTM_GETNSID);
+}
+
int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
struct rtmsg *rtm;
@@ -92,6 +96,20 @@ int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char
return 0;
}
+int sd_rtnl_message_route_set_tos(sd_netlink_message *m, unsigned char tos) {
+ struct rtmsg *rtm;
+
+ assert_return(m, -EINVAL);
+ assert_return(m->hdr, -EINVAL);
+ assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
+
+ rtm = NLMSG_DATA(m->hdr);
+
+ rtm->rtm_tos = tos;
+
+ return 0;
+}
+
int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
struct rtmsg *rtm;
@@ -336,7 +354,7 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
return r;
if (nlmsg_type == RTM_NEWNEXTHOP)
- (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
+ (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
nhm = NLMSG_DATA((*ret)->hdr);
@@ -1202,3 +1220,24 @@ int sd_rtnl_message_new_mdb(
return 0;
}
+
+int sd_rtnl_message_new_nsid(
+ sd_netlink *rtnl,
+ sd_netlink_message **ret,
+ uint16_t nlmsg_type) {
+
+ struct rtgenmsg *rt;
+ int r;
+
+ assert_return(rtnl_message_type_is_nsid(nlmsg_type), -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ r = message_new(rtnl, ret, nlmsg_type);
+ if (r < 0)
+ return r;
+
+ rt = NLMSG_DATA((*ret)->hdr);
+ rt->rtgen_family = AF_UNSPEC;
+
+ return 0;
+}
diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c
index 000a50e..49d000d 100644
--- a/src/libsystemd/sd-netlink/netlink-message.c
+++ b/src/libsystemd/sd-netlink/netlink-message.c
@@ -17,9 +17,6 @@
#define GET_CONTAINER(m, i) ((struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset))
-#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
-#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
-
int message_new_empty(sd_netlink *nl, sd_netlink_message **ret) {
sd_netlink_message *m;
@@ -789,32 +786,6 @@ int sd_netlink_message_read_data(sd_netlink_message *m, uint16_t attr_type, size
if (ret_data) {
void *data;
- data = memdup(attr_data, r);
- if (!data)
- return -ENOMEM;
-
- *ret_data = data;
- }
-
- if (ret_size)
- *ret_size = r;
-
- return r;
-}
-
-int sd_netlink_message_read_data_suffix0(sd_netlink_message *m, uint16_t attr_type, size_t *ret_size, void **ret_data) {
- void *attr_data;
- int r;
-
- assert_return(m, -EINVAL);
-
- r = netlink_message_read_internal(m, attr_type, &attr_data, NULL);
- if (r < 0)
- return r;
-
- if (ret_data) {
- void *data;
-
data = memdup_suffix0(attr_data, r);
if (!data)
return -ENOMEM;
diff --git a/src/libsystemd/sd-netlink/netlink-types-genl.c b/src/libsystemd/sd-netlink/netlink-types-genl.c
index 6fe9adc..226ac86 100644
--- a/src/libsystemd/sd-netlink/netlink-types-genl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-genl.c
@@ -199,6 +199,7 @@ static const NLAPolicy genl_nl80211_policies[] = {
[NL80211_ATTR_SSID] = BUILD_POLICY_WITH_SIZE(BINARY, IEEE80211_MAX_SSID_LEN),
[NL80211_ATTR_STATUS_CODE] = BUILD_POLICY(U16),
[NL80211_ATTR_4ADDR] = BUILD_POLICY(U8),
+ [NL80211_ATTR_NETNS_FD] = BUILD_POLICY(U32),
};
/***************** genl wireguard type systems *****************/
diff --git a/src/libsystemd/sd-netlink/netlink-types-rtnl.c b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
index 0153456..e39a75c 100644
--- a/src/libsystemd/sd-netlink/netlink-types-rtnl.c
+++ b/src/libsystemd/sd-netlink/netlink-types-rtnl.c
@@ -17,6 +17,7 @@
#include <linux/if_tunnel.h>
#include <linux/ip.h>
#include <linux/l2tp.h>
+#include <linux/net_namespace.h>
#include <linux/netlink.h>
#include <linux/nexthop.h>
#include <linux/nl80211.h>
@@ -123,6 +124,7 @@ static const NLAPolicy rtnl_link_info_data_bond_policies[] = {
[IFLA_BOND_AD_ACTOR_SYSTEM] = BUILD_POLICY_WITH_SIZE(ETHER_ADDR, ETH_ALEN),
[IFLA_BOND_TLB_DYNAMIC_LB] = BUILD_POLICY(U8),
[IFLA_BOND_PEER_NOTIF_DELAY] = BUILD_POLICY(U32),
+ [IFLA_BOND_MISSED_MAX] = BUILD_POLICY(U8),
};
static const NLAPolicy rtnl_link_info_data_bridge_policies[] = {
@@ -306,6 +308,7 @@ static const NLAPolicy rtnl_link_info_data_macvlan_policies[] = {
[IFLA_MACVLAN_MACADDR_COUNT] = BUILD_POLICY(U32),
[IFLA_MACVLAN_BC_QUEUE_LEN] = BUILD_POLICY(U32),
[IFLA_MACVLAN_BC_QUEUE_LEN_USED] = BUILD_POLICY(U32),
+ [IFLA_MACVLAN_BC_CUTOFF] = BUILD_POLICY(S32),
};
static const NLAPolicy rtnl_link_info_data_tun_policies[] = {
@@ -1185,6 +1188,13 @@ static const NLAPolicy rtnl_mdb_policies[] = {
DEFINE_POLICY_SET(rtnl_mdb);
+static const NLAPolicy rtnl_nsid_policies[] = {
+ [NETNSA_FD] = BUILD_POLICY(S32),
+ [NETNSA_NSID] = BUILD_POLICY(U32),
+};
+
+DEFINE_POLICY_SET(rtnl_nsid);
+
static const NLAPolicy rtnl_policies[] = {
[RTM_NEWLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
[RTM_DELLINK] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_link, sizeof(struct ifinfomsg)),
@@ -1220,6 +1230,9 @@ static const NLAPolicy rtnl_policies[] = {
[RTM_NEWMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_DELMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
[RTM_GETMDB] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_mdb, sizeof(struct br_port_msg)),
+ [RTM_NEWNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
+ [RTM_DELNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
+ [RTM_GETNSID] = BUILD_POLICY_NESTED_WITH_SIZE(rtnl_nsid, sizeof(struct rtgenmsg)),
};
DEFINE_POLICY_SET(rtnl);
diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c
index 832159a..9061609 100644
--- a/src/libsystemd/sd-netlink/netlink-util.c
+++ b/src/libsystemd/sd-netlink/netlink-util.c
@@ -11,6 +11,154 @@
#include "process-util.h"
#include "strv.h"
+static int parse_newlink_message(
+ sd_netlink_message *message,
+ char **ret_name,
+ char ***ret_altnames) {
+
+ _cleanup_strv_free_ char **altnames = NULL;
+ int r, ifindex;
+
+ assert(message);
+
+ uint16_t type;
+ r = sd_netlink_message_get_type(message, &type);
+ if (r < 0)
+ return r;
+ if (type != RTM_NEWLINK)
+ return -EPROTO;
+
+ r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
+ if (r < 0)
+ return r;
+ if (ifindex <= 0)
+ return -EPROTO;
+
+ if (ret_altnames) {
+ r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &altnames);
+ if (r < 0 && r != -ENODATA)
+ return r;
+ }
+
+ if (ret_name) {
+ r = sd_netlink_message_read_string_strdup(message, IFLA_IFNAME, ret_name);
+ if (r < 0)
+ return r;
+ }
+
+ if (ret_altnames)
+ *ret_altnames = TAKE_PTR(altnames);
+
+ return ifindex;
+}
+
+int rtnl_get_ifname_full(sd_netlink **rtnl, int ifindex, char **ret_name, char ***ret_altnames) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r;
+
+ assert(ifindex > 0);
+
+ /* This is similar to if_indextoname(), but also optionally provides alternative names. */
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, message, 0, &reply);
+ if (r < 0)
+ return r;
+
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+}
+
+int rtnl_resolve_ifname_full(
+ sd_netlink **rtnl,
+ ResolveInterfaceNameFlag flags,
+ const char *name,
+ char **ret_name,
+ char ***ret_altnames) {
+
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r;
+
+ assert(name);
+ assert(flags > 0);
+
+ /* This is similar to if_nametoindex(), but also resolves alternative names and decimal formatted
+ * ifindex too. Returns ifindex, and optionally provides the main interface name and alternative
+ * names.*/
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ /* First, use IFLA_IFNAME */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_MAIN) && ifname_valid(name)) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(message, IFLA_IFNAME, name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, message, 0, &reply);
+ if (r >= 0)
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+ if (r != -ENODEV)
+ return r;
+ }
+
+ /* Next, try IFLA_ALT_IFNAME */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_ALTERNATIVE) &&
+ ifname_valid_full(name, IFNAME_VALID_ALTERNATIVE)) {
+ _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
+
+ r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_message_append_string(message, IFLA_ALT_IFNAME, name);
+ if (r < 0)
+ return r;
+
+ r = sd_netlink_call(*rtnl, message, 0, &reply);
+ if (r >= 0)
+ return parse_newlink_message(reply, ret_name, ret_altnames);
+ /* The kernels older than 76c9ac0ee878f6693d398d3a95ccaf85e1f597a6 (v5.5) return -EINVAL. */
+ if (!IN_SET(r, -ENODEV, -EINVAL))
+ return r;
+ }
+
+ /* Finally, assume the string is a decimal formatted ifindex. */
+ if (FLAGS_SET(flags, RESOLVE_IFNAME_NUMERIC)) {
+ int ifindex;
+
+ ifindex = parse_ifindex(name);
+ if (ifindex <= 0)
+ return -ENODEV;
+
+ return rtnl_get_ifname_full(rtnl, ifindex, ret_name, ret_altnames);
+ }
+
+ return -ENODEV;
+}
+
static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL;
int r;
@@ -20,6 +168,13 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
assert(name);
/* Assign the requested name. */
+
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
r = sd_rtnl_message_new_link(*rtnl, &message, RTM_SETLINK, ifindex);
if (r < 0)
return r;
@@ -31,6 +186,37 @@ static int set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
return sd_netlink_call(*rtnl, message, 0, NULL);
}
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name) {
+ _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
+ int r, ifindex;
+
+ assert(orig_name);
+ assert(new_name);
+
+ /* This does not check alternative names. Callers must check the requested name is not used as an
+ * alternative name. */
+
+ if (streq(orig_name, new_name))
+ return 0;
+
+ if (!ifname_valid(new_name))
+ return -EINVAL;
+
+ if (!rtnl)
+ rtnl = &our_rtnl;
+ if (!*rtnl) {
+ r = sd_netlink_open(rtnl);
+ if (r < 0)
+ return r;
+ }
+
+ ifindex = rtnl_resolve_ifname(rtnl, orig_name);
+ if (ifindex < 0)
+ return ifindex;
+
+ return set_link_name(rtnl, ifindex, new_name);
+}
+
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const *alternative_names) {
_cleanup_strv_free_ char **original_altnames = NULL, **new_altnames = NULL;
bool altname_deleted = false;
@@ -204,38 +390,6 @@ int rtnl_set_link_properties(
return 0;
}
-int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
- _cleanup_strv_free_ char **names = NULL;
- int r;
-
- assert(rtnl);
- assert(ifindex > 0);
- assert(ret);
-
- if (!*rtnl) {
- r = sd_netlink_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, ifindex);
- if (r < 0)
- return r;
-
- r = sd_netlink_call(*rtnl, message, 0, &reply);
- if (r < 0)
- return r;
-
- r = sd_netlink_message_read_strv(reply, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &names);
- if (r < 0 && r != -ENODATA)
- return r;
-
- *ret = TAKE_PTR(names);
-
- return 0;
-}
-
static int rtnl_update_link_alternative_names(
sd_netlink **rtnl,
uint16_t nlmsg_type,
@@ -336,92 +490,6 @@ int rtnl_set_link_alternative_names_by_ifname(
return 0;
}
-int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret) {
- _cleanup_(sd_netlink_unrefp) sd_netlink *our_rtnl = NULL;
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL, *reply = NULL;
- int r, ifindex;
-
- assert(name);
-
- /* This returns ifindex and the main interface name. */
-
- if (!ifname_valid_full(name, IFNAME_VALID_ALTERNATIVE))
- return -EINVAL;
-
- if (!rtnl)
- rtnl = &our_rtnl;
- if (!*rtnl) {
- r = sd_netlink_open(rtnl);
- if (r < 0)
- return r;
- }
-
- r = sd_rtnl_message_new_link(*rtnl, &message, RTM_GETLINK, 0);
- if (r < 0)
- return r;
-
- r = sd_netlink_message_append_string(message, IFLA_ALT_IFNAME, name);
- if (r < 0)
- return r;
-
- r = sd_netlink_call(*rtnl, message, 0, &reply);
- if (r == -EINVAL)
- return -ENODEV; /* The device doesn't exist */
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_link_get_ifindex(reply, &ifindex);
- if (r < 0)
- return r;
- assert(ifindex > 0);
-
- if (ret) {
- r = sd_netlink_message_read_string_strdup(reply, IFLA_IFNAME, ret);
- if (r < 0)
- return r;
- }
-
- return ifindex;
-}
-
-int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name) {
- int r;
-
- /* Like if_nametoindex, but resolves "alternative names" too. */
-
- assert(name);
-
- r = if_nametoindex(name);
- if (r > 0)
- return r;
-
- return rtnl_resolve_link_alternative_name(rtnl, name, NULL);
-}
-
-int rtnl_resolve_interface(sd_netlink **rtnl, const char *name) {
- int r;
-
- /* Like rtnl_resolve_ifname, but resolves interface numbers too. */
-
- assert(name);
-
- r = parse_ifindex(name);
- if (r > 0)
- return r;
- assert(r < 0);
-
- return rtnl_resolve_ifname(rtnl, name);
-}
-
-int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
- int r;
-
- r = rtnl_resolve_interface(rtnl, name);
- if (r < 0)
- return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
- return r;
-}
-
int rtnl_get_link_info(
sd_netlink **rtnl,
int ifindex,
@@ -441,7 +509,7 @@ int rtnl_get_link_info(
assert(rtnl);
assert(ifindex > 0);
- if (!ret_iftype && !ret_flags)
+ if (!ret_iftype && !ret_flags && !ret_kind && !ret_hw_addr && !ret_permanent_hw_addr)
return 0;
if (!*rtnl) {
@@ -575,121 +643,6 @@ int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void
return 0;
}
-MultipathRoute *multipath_route_free(MultipathRoute *m) {
- if (!m)
- return NULL;
-
- free(m->ifname);
-
- return mfree(m);
-}
-
-int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret) {
- _cleanup_(multipath_route_freep) MultipathRoute *n = NULL;
- _cleanup_free_ char *ifname = NULL;
-
- assert(m);
- assert(ret);
-
- if (m->ifname) {
- ifname = strdup(m->ifname);
- if (!ifname)
- return -ENOMEM;
- }
-
- n = new(MultipathRoute, 1);
- if (!n)
- return -ENOMEM;
-
- *n = (MultipathRoute) {
- .gateway = m->gateway,
- .weight = m->weight,
- .ifindex = m->ifindex,
- .ifname = TAKE_PTR(ifname),
- };
-
- *ret = TAKE_PTR(n);
-
- return 0;
-}
-
-int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret) {
- _cleanup_ordered_set_free_free_ OrderedSet *set = NULL;
- int r;
-
- assert(rtnh);
- assert(IN_SET(family, AF_INET, AF_INET6));
-
- if (size < sizeof(struct rtnexthop))
- return -EBADMSG;
-
- for (; size >= sizeof(struct rtnexthop); ) {
- _cleanup_(multipath_route_freep) MultipathRoute *m = NULL;
-
- if (NLMSG_ALIGN(rtnh->rtnh_len) > size)
- return -EBADMSG;
-
- if (rtnh->rtnh_len < sizeof(struct rtnexthop))
- return -EBADMSG;
-
- m = new(MultipathRoute, 1);
- if (!m)
- return -ENOMEM;
-
- *m = (MultipathRoute) {
- .ifindex = rtnh->rtnh_ifindex,
- .weight = rtnh->rtnh_hops,
- };
-
- if (rtnh->rtnh_len > sizeof(struct rtnexthop)) {
- size_t len = rtnh->rtnh_len - sizeof(struct rtnexthop);
-
- for (struct rtattr *attr = RTNH_DATA(rtnh); RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
- if (attr->rta_type == RTA_GATEWAY) {
- if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(family)))
- return -EBADMSG;
-
- m->gateway.family = family;
- memcpy(&m->gateway.address, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(family));
- break;
- } else if (attr->rta_type == RTA_VIA) {
- uint16_t gw_family;
-
- if (family != AF_INET)
- return -EINVAL;
-
- if (attr->rta_len < RTA_LENGTH(sizeof(uint16_t)))
- return -EBADMSG;
-
- gw_family = *(uint16_t *) RTA_DATA(attr);
-
- if (gw_family != AF_INET6)
- return -EBADMSG;
-
- if (attr->rta_len != RTA_LENGTH(FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family)))
- return -EBADMSG;
-
- memcpy(&m->gateway, RTA_DATA(attr), FAMILY_ADDRESS_SIZE(gw_family) + sizeof(gw_family));
- break;
- }
- }
- }
-
- r = ordered_set_ensure_put(&set, NULL, m);
- if (r < 0)
- return r;
-
- TAKE_PTR(m);
-
- size -= NLMSG_ALIGN(rtnh->rtnh_len);
- rtnh = RTNH_NEXT(rtnh);
- }
-
- if (ret)
- *ret = TAKE_PTR(set);
- return 0;
-}
-
bool netlink_pid_changed(sd_netlink *nl) {
/* We don't support people creating an nl connection and
* keeping it around over a fork(). Let's complain. */
diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h
index 369f5d5..4ba64f0 100644
--- a/src/libsystemd/sd-netlink/netlink-util.h
+++ b/src/libsystemd/sd-netlink/netlink-util.h
@@ -10,24 +10,32 @@
#include "ordered-set.h"
#include "socket-util.h"
+#define RTA_FLAGS(rta) ((rta)->rta_type & ~NLA_TYPE_MASK)
+#define RTA_TYPE(rta) ((rta)->rta_type & NLA_TYPE_MASK)
+
/* See struct rtvia in rtnetlink.h */
typedef struct RouteVia {
uint16_t family;
union in_addr_union address;
} _packed_ RouteVia;
-typedef struct MultipathRoute {
- RouteVia gateway;
- uint32_t weight;
- int ifindex;
- char *ifname;
-} MultipathRoute;
+int rtnl_get_ifname_full(sd_netlink **rtnl, int ifindex, char **ret_name, char ***ret_altnames);
-MultipathRoute *multipath_route_free(MultipathRoute *m);
-DEFINE_TRIVIAL_CLEANUP_FUNC(MultipathRoute*, multipath_route_free);
+typedef enum ResolveInterfaceNameFlag {
+ RESOLVE_IFNAME_MAIN = 1 << 0, /* resolve main interface name */
+ RESOLVE_IFNAME_ALTERNATIVE = 1 << 1, /* resolve alternative name */
+ RESOLVE_IFNAME_NUMERIC = 1 << 2, /* resolve decimal formatted ifindex */
+ _RESOLVE_IFNAME_ALL = RESOLVE_IFNAME_MAIN | RESOLVE_IFNAME_ALTERNATIVE | RESOLVE_IFNAME_NUMERIC,
+} ResolveInterfaceNameFlag;
-int multipath_route_dup(const MultipathRoute *m, MultipathRoute **ret);
+int rtnl_resolve_ifname_full(
+ sd_netlink **rtnl,
+ ResolveInterfaceNameFlag flags,
+ const char *name,
+ char **ret_name,
+ char ***ret_altnames);
+int rtnl_rename_link(sd_netlink **rtnl, const char *orig_name, const char *new_name);
int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name, char* const* alternative_names);
static inline int rtnl_append_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names) {
return rtnl_set_link_name(rtnl, ifindex, NULL, alternative_names);
@@ -43,14 +51,32 @@ int rtnl_set_link_properties(
uint32_t mtu,
uint32_t gso_max_size,
size_t gso_max_segments);
-int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret);
+static inline int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret) {
+ return rtnl_get_ifname_full(rtnl, ifindex, NULL, ret);
+}
int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names);
int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char* const *alternative_names);
int rtnl_delete_link_alternative_names(sd_netlink **rtnl, int ifindex, char* const *alternative_names);
-int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret);
-int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name);
-int rtnl_resolve_interface(sd_netlink **rtnl, const char *name);
-int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name);
+static inline int rtnl_resolve_link_alternative_name(sd_netlink **rtnl, const char *name, char **ret) {
+ return rtnl_resolve_ifname_full(rtnl, RESOLVE_IFNAME_ALTERNATIVE, name, ret, NULL);
+}
+static inline int rtnl_resolve_ifname(sd_netlink **rtnl, const char *name) {
+ return rtnl_resolve_ifname_full(rtnl, RESOLVE_IFNAME_MAIN | RESOLVE_IFNAME_ALTERNATIVE, name, NULL, NULL);
+}
+static inline int rtnl_resolve_interface(sd_netlink **rtnl, const char *name) {
+ return rtnl_resolve_ifname_full(rtnl, _RESOLVE_IFNAME_ALL, name, NULL, NULL);
+}
+static inline int rtnl_resolve_interface_or_warn(sd_netlink **rtnl, const char *name) {
+ int r;
+
+ assert(name);
+
+ r = rtnl_resolve_interface(rtnl, name);
+ if (r < 0)
+ return log_error_errno(r, "Failed to resolve interface \"%s\": %m", name);
+ return r;
+}
+
int rtnl_get_link_info(
sd_netlink **rtnl,
int ifindex,
@@ -103,8 +129,6 @@ int netlink_message_read_in_addr_union(sd_netlink_message *m, unsigned short typ
void rtattr_append_attribute_internal(struct rtattr *rta, unsigned short type, const void *data, size_t data_length);
int rtattr_append_attribute(struct rtattr **rta, unsigned short type, const void *data, size_t data_length);
-int rtattr_read_nexthop(const struct rtnexthop *rtnh, size_t size, int family, OrderedSet **ret);
-
void netlink_seal_message(sd_netlink *nl, sd_netlink_message *m);
size_t netlink_get_reply_callback_count(sd_netlink *nl);
diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c
index b6730b7..b347ee6 100644
--- a/src/libsystemd/sd-netlink/sd-netlink.c
+++ b/src/libsystemd/sd-netlink/sd-netlink.c
@@ -176,7 +176,7 @@ static int dispatch_rqueue(sd_netlink *nl, sd_netlink_message **ret) {
assert(nl);
assert(ret);
- if (ordered_set_size(nl->rqueue) <= 0) {
+ if (ordered_set_isempty(nl->rqueue)) {
/* Try to read a new message */
r = socket_read_message(nl);
if (r == -ENOBUFS) /* FIXME: ignore buffer overruns for now */
@@ -443,7 +443,7 @@ int sd_netlink_wait(sd_netlink *nl, uint64_t timeout_usec) {
assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- if (ordered_set_size(nl->rqueue) > 0)
+ if (!ordered_set_isempty(nl->rqueue))
return 0;
r = netlink_poll(nl, false, timeout_usec);
@@ -623,7 +623,7 @@ int sd_netlink_get_events(sd_netlink *nl) {
assert_return(nl, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- return ordered_set_size(nl->rqueue) == 0 ? POLLIN : 0;
+ return ordered_set_isempty(nl->rqueue) ? POLLIN : 0;
}
int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
@@ -633,7 +633,7 @@ int sd_netlink_get_timeout(sd_netlink *nl, uint64_t *timeout_usec) {
assert_return(timeout_usec, -EINVAL);
assert_return(!netlink_pid_changed(nl), -ECHILD);
- if (ordered_set_size(nl->rqueue) > 0) {
+ if (!ordered_set_isempty(nl->rqueue)) {
*timeout_usec = 0;
return 1;
}
diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c
index 13aedc4..cf19c48 100644
--- a/src/libsystemd/sd-netlink/test-netlink.c
+++ b/src/libsystemd/sd-netlink/test-netlink.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/* Make sure the net/if.h header is included before any linux/ one */
#include <net/if.h>
#include <netinet/ether.h>
#include <netinet/in.h>
@@ -681,6 +682,19 @@ TEST(rtnl_set_link_name) {
_cleanup_free_ char *resolved = NULL;
assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
assert_se(streq_ptr(resolved, "test-shortname"));
+ resolved = mfree(resolved);
+
+ assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname") >= 0);
+ assert_se(rtnl_rename_link(&rtnl, "test-shortname", "test-shortname2") >= 0);
+ assert_se(rtnl_rename_link(NULL, "test-shortname2", "test-shortname3") >= 0);
+
+ assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-additional-name", &resolved) == ifindex);
+ assert_se(streq_ptr(resolved, "test-shortname3"));
+ resolved = mfree(resolved);
+
+ assert_se(rtnl_resolve_link_alternative_name(&rtnl, "test-shortname3", &resolved) == ifindex);
+ assert_se(streq_ptr(resolved, "test-shortname3"));
+ resolved = mfree(resolved);
}
DEFINE_TEST_MAIN(LOG_DEBUG);
diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c
index 2059567..25c6e44 100644
--- a/src/libsystemd/sd-network/network-util.c
+++ b/src/libsystemd/sd-network/network-util.c
@@ -90,49 +90,48 @@ static const char *const link_online_state_table[_LINK_ONLINE_STATE_MAX] = {
DEFINE_STRING_TABLE_LOOKUP(link_online_state, LinkOnlineState);
-int parse_operational_state_range(const char *str, LinkOperationalStateRange *out) {
- LinkOperationalStateRange range = { _LINK_OPERSTATE_INVALID, _LINK_OPERSTATE_INVALID };
- _cleanup_free_ const char *min = NULL;
+int parse_operational_state_range(const char *s, LinkOperationalStateRange *ret) {
+ LinkOperationalStateRange range = LINK_OPERSTATE_RANGE_INVALID;
+ _cleanup_free_ char *buf = NULL;
const char *p;
- assert(str);
- assert(out);
-
- p = strchr(str, ':');
- if (p) {
- min = strndup(str, p - str);
+ assert(s);
+ assert(ret);
- if (!isempty(p + 1)) {
- range.max = link_operstate_from_string(p + 1);
- if (range.max < 0)
- return -EINVAL;
- }
- } else
- min = strdup(str);
+ /* allowed formats: "min", "min:", "min:max", ":max" */
- if (!min)
- return -ENOMEM;
+ if (isempty(s) || streq(s, ":"))
+ return -EINVAL;
- if (!isempty(min)) {
- range.min = link_operstate_from_string(min);
- if (range.min < 0)
+ p = strchr(s, ':');
+ if (!p || isempty(p + 1))
+ range.max = LINK_OPERSTATE_ROUTABLE;
+ else {
+ range.max = link_operstate_from_string(p + 1);
+ if (range.max < 0)
return -EINVAL;
}
- /* Fail on empty strings. */
- if (range.min == _LINK_OPERSTATE_INVALID && range.max == _LINK_OPERSTATE_INVALID)
- return -EINVAL;
+ if (p) {
+ buf = strndup(s, p - s);
+ if (!buf)
+ return -ENOMEM;
- if (range.min == _LINK_OPERSTATE_INVALID)
+ s = buf;
+ }
+
+ if (isempty(s))
range.min = LINK_OPERSTATE_MISSING;
- if (range.max == _LINK_OPERSTATE_INVALID)
- range.max = LINK_OPERSTATE_ROUTABLE;
+ else {
+ range.min = link_operstate_from_string(s);
+ if (range.min < 0)
+ return -EINVAL;
+ }
- if (range.min > range.max)
+ if (!operational_state_range_is_valid(&range))
return -EINVAL;
- *out = range;
-
+ *ret = range;
return 0;
}
diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h
index c47e271..6fc6015 100644
--- a/src/libsystemd/sd-network/network-util.h
+++ b/src/libsystemd/sd-network/network-util.h
@@ -79,8 +79,30 @@ typedef struct LinkOperationalStateRange {
LinkOperationalState max;
} LinkOperationalStateRange;
-#define LINK_OPERSTATE_RANGE_DEFAULT (LinkOperationalStateRange) { LINK_OPERSTATE_DEGRADED, \
- LINK_OPERSTATE_ROUTABLE }
-
-int parse_operational_state_range(const char *str, LinkOperationalStateRange *out);
+#define LINK_OPERSTATE_RANGE_DEFAULT \
+ (const LinkOperationalStateRange) { \
+ .min = LINK_OPERSTATE_DEGRADED, \
+ .max = LINK_OPERSTATE_ROUTABLE, \
+ }
+
+#define LINK_OPERSTATE_RANGE_INVALID \
+ (const LinkOperationalStateRange) { \
+ .min = _LINK_OPERSTATE_INVALID, \
+ .max = _LINK_OPERSTATE_INVALID, \
+ }
+
+int parse_operational_state_range(const char *s, LinkOperationalStateRange *ret);
int network_link_get_operational_state(int ifindex, LinkOperationalState *ret);
+
+static inline bool operational_state_is_valid(LinkOperationalState s) {
+ return s >= 0 && s < _LINK_OPERSTATE_MAX;
+}
+static inline bool operational_state_range_is_valid(const LinkOperationalStateRange *range) {
+ return range &&
+ operational_state_is_valid(range->min) &&
+ operational_state_is_valid(range->max) &&
+ range->min <= range->max;
+}
+static inline bool operational_state_is_in_range(LinkOperationalState s, const LinkOperationalStateRange *range) {
+ return range && range->min <= s && s <= range->max;
+}
diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c
index cf3c400..9d11dce 100644
--- a/src/libsystemd/sd-network/sd-network.c
+++ b/src/libsystemd/sd-network/sd-network.c
@@ -394,7 +394,7 @@ int sd_network_monitor_new(sd_network_monitor **m, const char *category) {
sd_network_monitor* sd_network_monitor_unref(sd_network_monitor *m) {
if (m)
- (void) close_nointr(MONITOR_TO_FD(m));
+ (void) close(MONITOR_TO_FD(m));
return NULL;
}
diff --git a/src/libsystemd/sd-path/sd-path.c b/src/libsystemd/sd-path/sd-path.c
index 7290d1c..8edbde9 100644
--- a/src/libsystemd/sd-path/sd-path.c
+++ b/src/libsystemd/sd-path/sd-path.c
@@ -443,7 +443,7 @@ _public_ int sd_path_lookup(uint64_t type, const char *suffix, char **path) {
}
static int search_from_environment(
- char ***list,
+ char ***ret,
const char *env_home,
const char *home_suffix,
const char *env_search,
@@ -455,7 +455,7 @@ static int search_from_environment(
char *h = NULL;
int r;
- assert(list);
+ assert(ret);
if (env_search) {
e = secure_getenv(env_search);
@@ -465,7 +465,7 @@ static int search_from_environment(
return -ENOMEM;
if (env_search_sufficient) {
- *list = TAKE_PTR(l);
+ *ret = TAKE_PTR(l);
return 0;
}
}
@@ -506,7 +506,7 @@ static int search_from_environment(
return -ENOMEM;
}
- *list = TAKE_PTR(l);
+ *ret = TAKE_PTR(l);
return 0;
}
@@ -516,15 +516,15 @@ static int search_from_environment(
# define ARRAY_SBIN_BIN(x) x "bin"
#endif
-static int get_search(uint64_t type, char ***list) {
+static int get_search(uint64_t type, char ***ret) {
int r;
- assert(list);
+ assert(ret);
switch (type) {
case SD_PATH_SEARCH_BINARIES:
- return search_from_environment(list,
+ return search_from_environment(ret,
NULL,
".local/bin",
"PATH",
@@ -534,7 +534,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_LIBRARY_PRIVATE:
- return search_from_environment(list,
+ return search_from_environment(ret,
NULL,
".local/lib",
NULL,
@@ -544,7 +544,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_LIBRARY_ARCH:
- return search_from_environment(list,
+ return search_from_environment(ret,
NULL,
".local/lib/" LIB_ARCH_TUPLE,
"LD_LIBRARY_PATH",
@@ -553,7 +553,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_SHARED:
- return search_from_environment(list,
+ return search_from_environment(ret,
"XDG_DATA_HOME",
".local/share",
"XDG_DATA_DIRS",
@@ -563,7 +563,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_CONFIGURATION_FACTORY:
- return search_from_environment(list,
+ return search_from_environment(ret,
NULL,
NULL,
NULL,
@@ -573,7 +573,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_STATE_FACTORY:
- return search_from_environment(list,
+ return search_from_environment(ret,
NULL,
NULL,
NULL,
@@ -583,7 +583,7 @@ static int get_search(uint64_t type, char ***list) {
NULL);
case SD_PATH_SEARCH_CONFIGURATION:
- return search_from_environment(list,
+ return search_from_environment(ret,
"XDG_CONFIG_HOME",
".config",
"XDG_CONFIG_DIRS",
@@ -591,12 +591,18 @@ static int get_search(uint64_t type, char ***list) {
"/etc",
NULL);
- case SD_PATH_SEARCH_BINARIES_DEFAULT:
- return strv_from_nulstr(list, DEFAULT_PATH_NULSTR);
+ case SD_PATH_SEARCH_BINARIES_DEFAULT: {
+ char **t = strv_split(default_PATH(), ":");
+ if (!t)
+ return -ENOMEM;
+
+ *ret = t;
+ return 0;
+ }
case SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT:
case SD_PATH_SYSTEMD_SEARCH_USER_UNIT: {
- _cleanup_(lookup_paths_free) LookupPaths lp = {};
+ _cleanup_(lookup_paths_done) LookupPaths lp = {};
RuntimeScope scope = type == SD_PATH_SYSTEMD_SEARCH_SYSTEM_UNIT ?
RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER;
@@ -604,7 +610,7 @@ static int get_search(uint64_t type, char ***list) {
if (r < 0)
return r;
- *list = TAKE_PTR(lp.search_path);
+ *ret = TAKE_PTR(lp.search_path);
return 0;
}
@@ -618,7 +624,7 @@ static int get_search(uint64_t type, char ***list) {
if (!t)
return -ENOMEM;
- *list = t;
+ *ret = t;
return 0;
}
@@ -631,12 +637,12 @@ static int get_search(uint64_t type, char ***list) {
if (!t)
return -ENOMEM;
- *list = t;
+ *ret = t;
return 0;
}
case SD_PATH_SYSTEMD_SEARCH_NETWORK:
- return strv_from_nulstr(list, NETWORK_DIRS_NULSTR);
+ return strv_from_nulstr(ret, NETWORK_DIRS_NULSTR);
}