diff --git a/man/sd_journal_open.xml b/man/sd_journal_open.xml
index 8f62c966ea..8b7035fcc2 100644
--- a/man/sd_journal_open.xml
+++ b/man/sd_journal_open.xml
@@ -32,6 +32,7 @@
SD_JOURNAL_OS_ROOT
SD_JOURNAL_ALL_NAMESPACES
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
+ SD_JOURNAL_TAKE_DIRECTORY_FD
Open the system journal for reading
@@ -136,7 +137,13 @@
sd_journal_open_directory_fd() is similar to
sd_journal_open_directory(), but takes a file descriptor referencing a directory in the file
- system instead of an absolute file system path.
+ system instead of an absolute file system path. In addtion to the flags accepted by
+ sd_journal_open_directory(), this function also accepts
+ SD_JOURNAL_TAKE_DIRECTORY_FD. If SD_JOURNAL_TAKE_DIRECTORY_FD is
+ specified, the function will take the ownership of the specified file descriptor on success, and it will be
+ closed by sd_journal_close(), hence the caller of the function must not close the file
+ descriptor. When the flag is not specified, sd_journal_close() will not close the file
+ descriptor, so the caller should close it after sd_journal_close().
sd_journal_open_files() is similar to sd_journal_open() but takes a
NULL-terminated list of file paths to open. All files will be opened and interleaved
diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c
index 22f318f314..db74355842 100644
--- a/src/journal-remote/journal-upload.c
+++ b/src/journal-remote/journal-upload.c
@@ -21,6 +21,7 @@
#include "fs-util.h"
#include "glob-util.h"
#include "journal-upload.h"
+#include "journal-util.h"
#include "log.h"
#include "main-func.h"
#include "mkdir.h"
@@ -769,21 +770,17 @@ static int parse_argv(int argc, char *argv[]) {
static int open_journal(sd_journal **j) {
int r;
+ assert(j);
+
if (arg_directory)
r = sd_journal_open_directory(j, arg_directory, arg_journal_type);
else if (arg_file)
r = sd_journal_open_files(j, (const char**) arg_file, 0);
- else if (arg_machine) {
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
- /* FIXME: replace with D-Bus call OpenMachineRootDirectory() so that things also work with raw disk images */
- r = sd_journal_open_container(j, arg_machine, 0);
-#pragma GCC diagnostic pop
- } else if (arg_namespace)
- r = sd_journal_open_namespace(j, arg_namespace, (arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) |
- arg_namespace_flags | arg_journal_type);
+ else if (arg_machine)
+ r = journal_open_machine(j, arg_machine);
else
- r = sd_journal_open(j, (arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) | arg_journal_type);
+ r = sd_journal_open_namespace(j, arg_namespace,
+ (arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY) | arg_namespace_flags | arg_journal_type);
if (r < 0)
log_error_errno(r, "Failed to open %s: %m",
arg_directory ?: (arg_file ? "files" : "journal"));
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 8b36e2bbd2..c70b98a3b1 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -2348,7 +2348,6 @@ static int run(int argc, char *argv[]) {
_cleanup_(loop_device_unrefp) LoopDevice *loop_device = NULL;
_cleanup_(umount_and_freep) char *mounted_dir = NULL;
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
- _cleanup_close_ int machine_fd = -EBADF;
int n_shown, r, poll_fd = -EBADF;
setlocale(LC_ALL, "");
@@ -2467,35 +2466,9 @@ static int run(int argc, char *argv[]) {
r = sd_journal_open_files_fd(&j, (int[]) { STDIN_FILENO }, 1, 0);
else if (arg_file)
r = sd_journal_open_files(&j, (const char**) arg_file, 0);
- else if (arg_machine) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- int fd;
-
- if (geteuid() != 0)
- /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
- * the container, thus we need root privileges to override them. */
- return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
-
- r = sd_bus_open_system(&bus);
- if (r < 0)
- return log_error_errno(r, "Failed to open system bus: %m");
-
- r = bus_call_method(bus, bus_machine_mgr, "OpenMachineRootDirectory", &error, &reply, "s", arg_machine);
- if (r < 0)
- return log_error_errno(r, "Failed to open root directory: %s", bus_error_message(&error, r));
-
- r = sd_bus_message_read(reply, "h", &fd);
- if (r < 0)
- return bus_log_parse_error(r);
-
- machine_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (machine_fd < 0)
- return log_error_errno(errno, "Failed to duplicate file descriptor: %m");
-
- r = sd_journal_open_directory_fd(&j, machine_fd, SD_JOURNAL_OS_ROOT);
- } else
+ else if (arg_machine)
+ r = journal_open_machine(&j, arg_machine);
+ else
r = sd_journal_open_namespace(
&j,
arg_namespace,
diff --git a/src/libsystemd/sd-journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c
index 0124900517..d84b117783 100644
--- a/src/libsystemd/sd-journal/sd-journal.c
+++ b/src/libsystemd/sd-journal/sd-journal.c
@@ -2177,13 +2177,16 @@ _public_ int sd_journal_open_files(sd_journal **ret, const char **paths, int fla
return 0;
}
-#define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
+#define OPEN_DIRECTORY_FD_ALLOWED_FLAGS \
(SD_JOURNAL_OS_ROOT | \
- SD_JOURNAL_SYSTEM | SD_JOURNAL_CURRENT_USER )
+ SD_JOURNAL_SYSTEM | \
+ SD_JOURNAL_CURRENT_USER | \
+ SD_JOURNAL_TAKE_DIRECTORY_FD)
_public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
_cleanup_(sd_journal_closep) sd_journal *j = NULL;
struct stat st;
+ bool take_fd;
int r;
assert_return(ret, -EINVAL);
@@ -2196,7 +2199,8 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
if (!S_ISDIR(st.st_mode))
return -EBADFD;
- j = journal_new(flags, NULL, NULL);
+ take_fd = FLAGS_SET(flags, SD_JOURNAL_TAKE_DIRECTORY_FD);
+ j = journal_new(flags & ~SD_JOURNAL_TAKE_DIRECTORY_FD, NULL, NULL);
if (!j)
return -ENOMEM;
@@ -2209,6 +2213,8 @@ _public_ int sd_journal_open_directory_fd(sd_journal **ret, int fd, int flags) {
if (r < 0)
return r;
+ SET_FLAG(j->flags, SD_JOURNAL_TAKE_DIRECTORY_FD, take_fd);
+
*ret = TAKE_PTR(j);
return 0;
}
@@ -2288,6 +2294,9 @@ _public_ void sd_journal_close(sd_journal *j) {
hashmap_free(j->directories_by_path);
hashmap_free(j->directories_by_wd);
+ if (FLAGS_SET(j->flags, SD_JOURNAL_TAKE_DIRECTORY_FD))
+ safe_close(j->toplevel_fd);
+
safe_close(j->inotify_fd);
if (j->mmap) {
diff --git a/src/shared/journal-util.c b/src/shared/journal-util.c
index ea396fcc9b..d73d7c47d0 100644
--- a/src/shared/journal-util.c
+++ b/src/shared/journal-util.c
@@ -1,6 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "acl-util.h"
+#include "bus-error.h"
+#include "bus-locator.h"
+#include "bus-util.h"
+#include "fd-util.h"
#include "fs-util.h"
#include "hashmap.h"
#include "journal-internal.h"
@@ -140,3 +144,45 @@ int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_use
return r;
}
+
+int journal_open_machine(sd_journal **ret, const char *machine) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_(sd_journal_closep) sd_journal *j = NULL;
+ _cleanup_close_ int machine_fd = -EBADF;
+ int fd, r;
+
+ assert(ret);
+ assert(machine);
+
+ if (geteuid() != 0)
+ /* The file descriptor returned by OpenMachineRootDirectory() will be owned by users/groups of
+ * the container, thus we need root privileges to override them. */
+ return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Using the --machine= switch requires root privileges.");
+
+ r = sd_bus_open_system(&bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open system bus: %m");
+
+ r = bus_call_method(bus, bus_machine_mgr, "OpenMachineRootDirectory", &error, &reply, "s", machine);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open root directory of machine '%s': %s",
+ machine, bus_error_message(&error, r));
+
+ r = sd_bus_message_read(reply, "h", &fd);
+ if (r < 0)
+ return bus_log_parse_error(r);
+
+ machine_fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (machine_fd < 0)
+ return log_error_errno(errno, "Failed to duplicate file descriptor: %m");
+
+ r = sd_journal_open_directory_fd(&j, machine_fd, SD_JOURNAL_OS_ROOT | SD_JOURNAL_TAKE_DIRECTORY_FD);
+ if (r < 0)
+ return log_error_errno(r, "Failed to open journal in machine '%s': %m", machine);
+
+ TAKE_FD(machine_fd);
+ *ret = TAKE_PTR(j);
+ return 0;
+}
diff --git a/src/shared/journal-util.h b/src/shared/journal-util.h
index 86fcba058d..afad249c90 100644
--- a/src/shared/journal-util.h
+++ b/src/shared/journal-util.h
@@ -8,3 +8,4 @@
int journal_access_blocked(sd_journal *j);
int journal_access_check_and_warn(sd_journal *j, bool quiet, bool want_other_users);
+int journal_open_machine(sd_journal **ret, const char *machine);
diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h
index 4af540400d..7d2d75dd89 100644
--- a/src/systemd/sd-journal.h
+++ b/src/systemd/sd-journal.h
@@ -71,6 +71,7 @@ enum {
SD_JOURNAL_OS_ROOT = 1 << 4,
SD_JOURNAL_ALL_NAMESPACES = 1 << 5, /* Show all namespaces, not just the default or specified one */
SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE = 1 << 6, /* Show default namespace in addition to specified one */
+ SD_JOURNAL_TAKE_DIRECTORY_FD = 1 << 7, /* sd_journal_open_directory_fd() will take ownership of the provided file descriptor. */
SD_JOURNAL_SYSTEM_ONLY _sd_deprecated_ = SD_JOURNAL_SYSTEM /* old name */
};