<xi:include href="version-info.xml" xpointer="v187"/></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--forward-journal=</option></term>
+
+ <listitem><para>Forward the container's journal to the host by starting
+ <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ listening on a Unix socket that is bind-mounted into the container. The container's
+ <citerefentry><refentrytitle>systemd-journald</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ connects to the socket via the <varname>journal.forward_to_socket</varname> credential and streams
+ journal entries to the host in real-time. Takes a path to a journal file or directory where the received
+ entries will be stored. If the path ends in <literal>.journal</literal>, entries are written to a single
+ file; otherwise, entries are split per host into the specified directory.</para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--forward-journal-max-use=<replaceable>BYTES</replaceable></option></term>
+ <term><option>--forward-journal-keep-free=<replaceable>BYTES</replaceable></option></term>
+ <term><option>--forward-journal-max-file-size=<replaceable>BYTES</replaceable></option></term>
+ <term><option>--forward-journal-max-files=<replaceable>N</replaceable></option></term>
+
+ <listitem><para>These options configure the corresponding settings of
+ <citerefentry><refentrytitle>systemd-journal-remote</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ when forwarding journal entries from the container. See
+ <citerefentry><refentrytitle>journal-remote.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ for the descriptions of these settings.</para>
+
+ <xi:include href="version-info.xml" xpointer="v261"/></listitem>
+ </varlistentry>
+
</variablelist>
</refsect2><refsect2>
--network-ipvlan --network-veth-extra --network-zone -p --port --system-call-filter --overlay
--overlay-ro --settings --rlimit --hostname --no-new-privileges --oom-score-adjust --cpu-affinity
--resolv-conf --timezone --root-hash-sig --background --oci-bundle --verity-data
- --restrict-address-families'
+ --restrict-address-families
+ --forward-journal --forward-journal-max-use --forward-journal-keep-free
+ --forward-journal-max-file-size --forward-journal-max-files'
)
_init_completion || return
"--notify-ready=[Control when the ready notification is sent]:options:(yes no)" \
"--suppress-sync=[Control whether to suppress disk synchronization for the container payload]:options:(yes no)" \
'--restrict-address-families=[Restrict socket address families accessible in the container.]: : _message "address families"' \
+ '--forward-journal=[Forward the container journal to the host via systemd-journal-remote.]: : _files' \
+ '--forward-journal-max-use=[Maximum disk space used by forwarded journal files.]: : _message bytes' \
+ '--forward-journal-keep-free=[Disk space to keep free for forwarded journal files.]: : _message bytes' \
+ '--forward-journal-max-file-size=[Maximum size of individual forwarded journal files.]: : _message bytes' \
+ '--forward-journal-max-files=[Maximum number of forwarded journal files.]: : _message number' \
'*:: : _normal'
#include "alloc-util.h"
#include "fs-util.h"
#include "log.h"
+#include "mkdir.h"
#include "path-lookup.h"
#include "path-util.h"
#include "stat-util.h"
return 1;
}
+int runtime_directory_make(RuntimeScope scope, const char *subdir, char **ret_dir, char **ret_dir_destroy) {
+ _cleanup_free_ char *dir = NULL, *destroy = NULL;
+ int r;
+
+ assert(subdir);
+ assert(ret_dir);
+ assert(ret_dir_destroy);
+
+ /* Use runtime_directory() (not _generic()) so that when we run in a systemd service
+ * with RuntimeDirectory= set, we pick up $RUNTIME_DIRECTORY and place our stuff into the
+ * directory the service manager prepared for us. When the env var is unset, we fall back
+ * to the provided subdirectory under /run (or the $XDG_RUNTIME_DIR equivalent in user scope)
+ * and take care of creation and destruction ourselves. */
+ r = runtime_directory(scope, subdir, &dir);
+ if (r < 0)
+ return r;
+
+ if (r > 0) {
+ /* $RUNTIME_DIRECTORY was not set, so we got the fallback path and need to create and
+ * clean up the directory ourselves. */
+ destroy = strdup(dir);
+ if (!destroy)
+ return -ENOMEM;
+
+ r = mkdir_p(dir, 0755);
+ if (r < 0)
+ return r;
+ }
+
+ /* When $RUNTIME_DIRECTORY is set the service manager created the directory for us and
+ * will destroy it (or preserve it, per RuntimeDirectoryPreserve=) when the service stops. */
+
+ *ret_dir = TAKE_PTR(dir);
+ *ret_dir_destroy = TAKE_PTR(destroy);
+
+ return 0;
+}
+
static const char* const user_data_unit_paths[] = {
"/usr/local/lib/systemd/user",
"/usr/local/share/systemd/user",
int config_directory_generic(RuntimeScope scope, const char *suffix, char **ret);
int runtime_directory_generic(RuntimeScope scope, const char *suffix, char **ret);
int runtime_directory(RuntimeScope scope, const char *fallback_suffix, char **ret);
+int runtime_directory_make(RuntimeScope scope, const char *subdir, char **ret_dir, char **ret_dir_destroy);
/* We don't treat /etc/xdg/systemd/ in these functions as the xdg base dir spec suggests because we assume
* that is a link to /etc/systemd/ anyway. */
#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
+#include "fork-notify.h"
#include "format-table.h"
#include "format-util.h"
#include "fs-util.h"
#include "pager.h"
#include "parse-argument.h"
#include "parse-util.h"
+#include "path-lookup.h"
#include "path-util.h"
#include "pidref.h"
#include "polkit-agent.h"
/* The notify socket inside the container it can use to talk to nspawn using the sd_notify(3) protocol */
#define NSPAWN_NOTIFY_SOCKET_PATH "/run/host/notify"
#define NSPAWN_MOUNT_TUNNEL "/run/host/incoming"
+#define NSPAWN_JOURNAL_SOCKET_PATH "/run/host/journal/socket"
#define EXIT_FORCE_RESTART 133
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
static bool arg_cleanup = false;
static bool arg_ask_password = true;
+static char *arg_forward_journal = NULL;
+static uint64_t arg_forward_journal_max_use = UINT64_MAX;
+static uint64_t arg_forward_journal_keep_free = UINT64_MAX;
+static uint64_t arg_forward_journal_max_file_size = UINT64_MAX;
+static uint64_t arg_forward_journal_max_files = UINT64_MAX;
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
STATIC_DESTRUCTOR_REGISTER(arg_template, freep);
STATIC_DESTRUCTOR_REGISTER(arg_settings_filename, freep);
STATIC_DESTRUCTOR_REGISTER(arg_image_policy, image_policy_freep);
STATIC_DESTRUCTOR_REGISTER(arg_background, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_forward_journal, freep);
static int parse_private_users(
const char *s,
arg_settings_mask |= SETTING_LINK_JOURNAL;
break;
+ OPTION_LONG("forward-journal", "FILE|DIR", "Forward the container's journal to the host"):
+ r = parse_path_argument(arg, /* suppress_root= */ false, &arg_forward_journal);
+ if (r < 0)
+ return r;
+ break;
+
+ OPTION_LONG("forward-journal-max-use", "BYTES", "Maximum disk space for forwarded journal"):
+ r = parse_size(arg, 1024, &arg_forward_journal_max_use);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --forward-journal-max-use= value: %s", optarg);
+ break;
+
+ OPTION_LONG("forward-journal-keep-free", "BYTES", "Minimum disk space to keep free"):
+ r = parse_size(arg, 1024, &arg_forward_journal_keep_free);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --forward-journal-keep-free= value: %s", optarg);
+ break;
+
+ OPTION_LONG("forward-journal-max-file-size", "BYTES", "Maximum size of individual journal files"):
+ r = parse_size(arg, 1024, &arg_forward_journal_max_file_size);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --forward-journal-max-file-size= value: %s", optarg);
+ break;
+
+ OPTION_LONG("forward-journal-max-files", "N", "Maximum number of journal files to keep"):
+ r = safe_atou64(arg, &arg_forward_journal_max_files);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse --forward-journal-max-files= value: %s", optarg);
+ break;
+
OPTION_GROUP("Mounts"): {}
OPTION_LONG("bind", "PATH[:PATH[:OPTIONS]]",
arg_caps_retain |= arg_private_network ? UINT64_C(1) << CAP_NET_ADMIN : 0;
arg_caps_retain &= ~minus;
+ if ((arg_forward_journal_max_use != UINT64_MAX ||
+ arg_forward_journal_keep_free != UINT64_MAX ||
+ arg_forward_journal_max_file_size != UINT64_MAX ||
+ arg_forward_journal_max_files != UINT64_MAX) && !arg_forward_journal)
+ return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--forward-journal-max-use=/--forward-journal-keep-free=/--forward-journal-max-file-size=/--forward-journal-max-files= require --forward-journal=.");
+
/* Make sure to parse environment before we reset the settings mask below */
r = parse_environment();
if (r < 0)
return TAKE_FD(fd);
}
-static int setup_unix_export_dir_outside(char **ret) {
+static int setup_unix_export_dir_outside(const char *runtime_dir, char **ret) {
int r;
+ assert(runtime_dir);
assert(ret);
if (arg_userns_mode == USER_NAMESPACE_MANAGED) {
}
_cleanup_free_ char *p = NULL;
- p = path_join("/run/systemd/nspawn/unix-export", arg_machine);
+ p = path_join(runtime_dir, "unix-export");
if (!p)
return log_oom();
}
static int run_container(
+ const char *runtime_dir,
const char *directory,
int mount_fd,
DissectedImage *dissected_image,
assert_se(sigaddset(&mask_chld, SIGCHLD) == 0);
/* Set up the unix export host directory on the host first */
- r = setup_unix_export_dir_outside(&unix_export_host_dir);
+ r = setup_unix_export_dir_outside(runtime_dir, &unix_export_host_dir);
if (r < 0)
return r;
return 0;
}
-static void cleanup_propagation_and_export_directories(void) {
- const char *p;
+static void cleanup_propagation_and_export_directories(const char *runtime_dir) {
+ _cleanup_free_ char *p = NULL;
- if (!arg_machine || arg_runtime_scope != RUNTIME_SCOPE_SYSTEM)
+ if (!runtime_dir || arg_userns_mode == USER_NAMESPACE_MANAGED)
return;
- p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
- (void) rm_rf(p, REMOVE_ROOT);
+ p = path_join("/run/systemd/nspawn/propagate", arg_machine);
+ if (p)
+ (void) rm_rf(p, REMOVE_ROOT);
- p = strjoina("/run/systemd/nspawn/unix-export/", arg_machine);
- (void) umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW);
- (void) rmdir(p);
+ free(p);
+ p = path_join(runtime_dir, "unix-export");
+ if (p) {
+ (void) umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW);
+ (void) rmdir(p);
+ }
}
static int do_cleanup(void) {
if (r < 0)
return r;
- cleanup_propagation_and_export_directories();
+ _cleanup_free_ char *subdir = path_join("systemd/nspawn", arg_machine);
+ if (!subdir)
+ return log_oom();
+
+ _cleanup_free_ char *runtime_dir = NULL;
+ r = runtime_directory(arg_runtime_scope, subdir, &runtime_dir);
+ if (r < 0)
+ return r;
+
+ cleanup_propagation_and_export_directories(runtime_dir);
return 0;
}
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
_cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
_cleanup_(sd_varlink_unrefp) sd_varlink *nsresource_link = NULL, *mountfsd_link = NULL;
+ _cleanup_free_ char *runtime_dir = NULL, *subdir = NULL;
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir_destroy = NULL;
+ _cleanup_(fork_notify_terminate) PidRef journal_remote_pidref = PIDREF_NULL;
log_setup();
} else
assert_not_reached();
+ subdir = path_join("systemd/nspawn", arg_machine);
+ if (!subdir) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = runtime_directory_make(
+ arg_runtime_scope,
+ subdir,
+ &runtime_dir,
+ &runtime_dir_destroy);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create runtime directory: %m");
+ goto finish;
+ }
+
/* Create a temporary place to mount stuff. */
r = mkdtemp_malloc("/tmp/nspawn-root-XXXXXX", &rootdir);
if (r < 0) {
expose_args.nfnl = nfnl;
}
+ if (arg_forward_journal) {
+ _cleanup_free_ char *socket_path = path_join(runtime_dir, "journal-remote-socket");
+ if (!socket_path) {
+ r = log_oom();
+ goto finish;
+ }
+
+ union sockaddr_union sa;
+ r = sockaddr_un_set_path(&sa.un, socket_path);
+ if (r < 0) {
+ log_error_errno(r, "Failed to set AF_UNIX path to '%s': %m", socket_path);
+ goto finish;
+ }
+
+ (void) sockaddr_un_unlink(&sa.un);
+
+ r = fork_journal_remote(
+ socket_path,
+ arg_forward_journal,
+ arg_forward_journal_max_use,
+ arg_forward_journal_keep_free,
+ arg_forward_journal_max_file_size,
+ arg_forward_journal_max_files,
+ &journal_remote_pidref);
+ if (r < 0)
+ goto finish;
+
+ CustomMount *cm = custom_mount_add(&arg_custom_mounts, &arg_n_custom_mounts, CUSTOM_MOUNT_BIND);
+ if (!cm) {
+ r = log_oom();
+ goto finish;
+ }
+
+ cm->source = TAKE_PTR(socket_path);
+ cm->read_only = true;
+ cm->destination = strdup(NSPAWN_JOURNAL_SOCKET_PATH);
+ if (!cm->destination) {
+ r = log_oom();
+ goto finish;
+ }
+
+ r = machine_credential_add(&arg_credentials, "journal.forward_to_socket", NSPAWN_JOURNAL_SOCKET_PATH, SIZE_MAX);
+ if (r == -EEXIST) {
+ log_error_errno(r, "Credential 'journal.forward_to_socket' already set via --set-credential=, refusing --forward-journal=.");
+ goto finish;
+ }
+ if (r < 0) {
+ log_error_errno(r, "Failed to add 'journal.forward_to_socket' credential: %m");
+ goto finish;
+ }
+ }
+
for (;;) {
r = run_container(
+ runtime_dir,
rootdir,
mount_fd,
dissected_image,
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
}
- if (arg_machine && arg_userns_mode != USER_NAMESPACE_MANAGED) {
- const char *p;
-
- p = strjoina("/run/systemd/nspawn/propagate/", arg_machine);
- (void) rm_rf(p, REMOVE_ROOT);
-
- p = strjoina("/run/systemd/nspawn/unix-export/", arg_machine);
- (void) umount2(p, MNT_DETACH|UMOUNT_NOFOLLOW);
- (void) rmdir(p);
- }
-
- cleanup_propagation_and_export_directories();
+ cleanup_propagation_and_export_directories(runtime_dir);
expose_port_flush(nfnl, arg_expose_ports, AF_INET, &expose_args.address4);
expose_port_flush(nfnl, arg_expose_ports, AF_INET6, &expose_args.address6);
#include <stdlib.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "build-path.h"
+#include "chase.h"
+#include "chattr-util.h"
#include "escape.h"
#include "event-util.h"
#include "exit-status.h"
+#include "fd-util.h"
#include "fork-notify.h"
#include "log.h"
#include "notify-recv.h"
#include "parse-util.h"
+#include "path-util.h"
#include "pidref.h"
#include "process-util.h"
#include "runtime-scope.h"
return fork_notify(argv, ret_pidref);
}
+
+int fork_journal_remote(
+ const char *listen_address,
+ const char *output,
+ uint64_t max_use,
+ uint64_t keep_free,
+ uint64_t max_file_size,
+ uint64_t max_files,
+ PidRef *ret_pidref) {
+
+ int r;
+
+ assert(listen_address);
+ assert(output);
+ assert(ret_pidref);
+
+ ChaseFlags chase_flags = CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY;
+ if (endswith(output, ".journal"))
+ chase_flags |= CHASE_PARENT;
+
+ _cleanup_close_ int fd = -EBADF;
+ r = chase(output, /* root= */ NULL, chase_flags, /* ret_path= */ NULL, &fd);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create journal directory for '%s': %m", output);
+
+ r = chattr_fd(fd, FS_NOCOW_FL, FS_NOCOW_FL);
+ if (r < 0)
+ log_debug_errno(r, "Failed to set NOCOW flag on journal directory for '%s', ignoring: %m", output);
+
+ _cleanup_free_ char *sd_socket_activate = NULL;
+ r = find_executable("systemd-socket-activate", &sd_socket_activate);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find systemd-socket-activate binary: %m");
+
+ _cleanup_free_ char *sd_journal_remote = NULL;
+ r = find_executable_full(
+ "systemd-journal-remote",
+ /* root= */ NULL,
+ STRV_MAKE(LIBEXECDIR),
+ /* use_path_envvar= */ true,
+ &sd_journal_remote,
+ /* ret_fd= */ NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to find systemd-journal-remote binary: %m");
+
+ _cleanup_strv_free_ char **argv = strv_new(
+ sd_socket_activate,
+ "--listen", listen_address,
+ sd_journal_remote,
+ "--output", output,
+ "--split-mode", endswith(output, ".journal") ? "none" : "host");
+ if (!argv)
+ return log_oom();
+
+ if (max_use != UINT64_MAX &&
+ strv_extendf(&argv, "--max-use=%" PRIu64, max_use) < 0)
+ return log_oom();
+
+ if (keep_free != UINT64_MAX &&
+ strv_extendf(&argv, "--keep-free=%" PRIu64, keep_free) < 0)
+ return log_oom();
+
+ if (max_file_size != UINT64_MAX &&
+ strv_extendf(&argv, "--max-file-size=%" PRIu64, max_file_size) < 0)
+ return log_oom();
+
+ if (max_files != UINT64_MAX &&
+ strv_extendf(&argv, "--max-files=%" PRIu64, max_files) < 0)
+ return log_oom();
+
+ r = fork_notify(/* argv= */ NULL, ret_pidref);
+ if (r < 0)
+ return r;
+ if (r == 0) {
+ /* In the child */
+ if (setenv("SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE",
+ "/dev/null",
+ /* overwrite= */ true) < 0) {
+ log_debug_errno(errno, "Failed to set $SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE: %m");
+ _exit(EXIT_MEMORY);
+ }
+
+ r = invoke_callout_binary(argv[0], argv);
+ log_debug_errno(r, "Failed to invoke %s: %m", argv[0]);
+ _exit(EXIT_EXEC);
+ }
+
+ return 0;
+}
void fork_notify_terminate_many(sd_event_source **array, size_t n);
int journal_fork(RuntimeScope scope, char * const *units, OutputMode output, PidRef *ret_pidref);
+
+int fork_journal_remote(
+ const char *listen_address,
+ const char *output,
+ uint64_t max_use,
+ uint64_t keep_free,
+ uint64_t max_file_size,
+ uint64_t max_files,
+ PidRef *ret_pidref);
return r;
log_debug("Binding SSH to AF_UNIX socket /run/host/unix-export/ssh\n"
- "→ connect via 'ssh unix/run/systemd/nspawn/unix-export/\?\?\?/ssh' from host");
+ "→ connect via 'ssh unix/run/systemd/nspawn/\?\?\?/unix-export/ssh' from host");
return 0;
}
if (!streq_ptr(p.service, "systemd-nspawn"))
return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), "Don't know how to SSH into '%s' container %s.", p.service, machine);
- r = runtime_directory_generic(scope, "systemd/nspawn/unix-export", &path);
+ r = runtime_directory_generic(scope, "systemd/nspawn", &path);
if (r < 0)
return log_error_errno(r, "Failed to determine runtime directory: %m");
- if (!path_extend(&path, machine, "ssh"))
+ if (!path_extend(&path, machine, "unix-export", "ssh"))
return log_oom();
r = is_socket(path);
#include "bus-locator.h"
#include "bus-util.h"
#include "capability-util.h"
-#include "chase.h"
-#include "chattr-util.h"
#include "common-signal.h"
#include "copy.h"
#include "discover-image.h"
#include "escape.h"
#include "ether-addr-util.h"
#include "event-util.h"
-#include "exit-status.h"
#include "extract-word.h"
#include "fd-util.h"
#include "fileio.h"
return 0;
}
-static int start_systemd_journal_remote(
- const char *scope,
- unsigned port,
- const char *sd_socket_activate,
- char **ret_listen_address,
- PidRef *ret_pidref) {
-
- int r;
-
- assert(scope);
- assert(sd_socket_activate);
-
- _cleanup_free_ char *scope_prefix = NULL;
- r = unit_name_to_prefix(scope, &scope_prefix);
- if (r < 0)
- return log_error_errno(r, "Failed to strip .scope suffix from scope: %m");
-
- _cleanup_free_ char *listen_address = NULL;
- if (asprintf(&listen_address, "vsock:2:%u", port) < 0)
- return log_oom();
-
- _cleanup_free_ char *sd_journal_remote = NULL;
- r = find_executable_full(
- "systemd-journal-remote",
- /* root= */ NULL,
- STRV_MAKE(LIBEXECDIR),
- /* use_path_envvar= */ true, /* systemd-journal-remote should be installed in
- * LIBEXECDIR, but for supporting fancy setups. */
- &sd_journal_remote,
- /* ret_fd= */ NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to find systemd-journal-remote binary: %m");
-
- _cleanup_strv_free_ char **argv = strv_new(
- sd_socket_activate,
- "--listen", listen_address,
- sd_journal_remote,
- "--output", arg_forward_journal,
- "--split-mode", endswith(arg_forward_journal, ".journal") ? "none" : "host");
- if (!argv)
- return log_oom();
-
- if (arg_forward_journal_max_use != UINT64_MAX &&
- strv_extendf(&argv, "--max-use=%" PRIu64, arg_forward_journal_max_use) < 0)
- return log_oom();
-
- if (arg_forward_journal_keep_free != UINT64_MAX &&
- strv_extendf(&argv, "--keep-free=%" PRIu64, arg_forward_journal_keep_free) < 0)
- return log_oom();
-
- if (arg_forward_journal_max_file_size != UINT64_MAX &&
- strv_extendf(&argv, "--max-file-size=%" PRIu64, arg_forward_journal_max_file_size) < 0)
- return log_oom();
-
- if (arg_forward_journal_max_files != UINT64_MAX &&
- strv_extendf(&argv, "--max-files=%" PRIu64, arg_forward_journal_max_files) < 0)
- return log_oom();
-
- r = fork_notify(/* argv= */ NULL, ret_pidref);
- if (r < 0)
- return r;
- if (r == 0) {
- /* In the child */
- if (setenv("SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE",
- "/dev/null",
- /* overwrite= */ true) < 0) {
- log_debug_errno(errno, "Failed to set $SYSTEMD_JOURNAL_REMOTE_CONFIG_FILE: %m");
- _exit(EXIT_MEMORY);
- }
-
- r = invoke_callout_binary(argv[0], argv);
- log_error_errno(r, "Failed to invoke %s: %m", argv[0]);
- _exit(EXIT_EXEC);
- }
-
- if (ret_listen_address)
- *ret_listen_address = TAKE_PTR(listen_address);
-
- return 0;
-}
-
static int discover_root(char **ret) {
int r;
_cleanup_(dissected_image_unrefp) DissectedImage *image = NULL;
return log_oom();
/* Create our runtime directory. We need this for the QMP varlink control socket, the QEMU
- * config file, TPM state, virtiofsd sockets, runtime mounts, and SSH key material.
- *
- * Use runtime_directory() (not _generic()) so that when vmspawn runs in a systemd service
- * with RuntimeDirectory= set, we pick up $RUNTIME_DIRECTORY and place our stuff into the
- * directory the service manager prepared for us. When the env var is unset, we fall back
- * to /run/systemd/vmspawn/<machine>/ (or the $XDG_RUNTIME_DIR equivalent in user scope)
- * and take care of creation and destruction ourselves. */
+ * config file, TPM state, virtiofsd sockets, runtime mounts, and SSH key material. */
_cleanup_free_ char *runtime_dir = NULL, *runtime_dir_suffix = NULL;
_cleanup_(rm_rf_physical_and_freep) char *runtime_dir_destroy = NULL;
if (!runtime_dir_suffix)
return log_oom();
- r = runtime_directory(arg_runtime_scope, runtime_dir_suffix, &runtime_dir);
+ r = runtime_directory_make(arg_runtime_scope, runtime_dir_suffix, &runtime_dir, &runtime_dir_destroy);
if (r < 0)
- return log_error_errno(r, "Failed to determine runtime directory: %m");
- if (r > 0) {
- /* $RUNTIME_DIRECTORY was not set, so we got the fallback path and need to create and
- * clean up the directory ourselves.
- *
- * If a previous vmspawn instance was killed without cleanup (e.g. SIGKILL), the directory may
- * already exist with stale contents. This is harmless: varlink's sockaddr_un_unlink() removes stale
- * sockets before bind(), and other files (QEMU config, SSH keys) are created fresh. This matches
- * nspawn's approach of not proactively cleaning stale runtime directories. */
- r = mkdir_p(runtime_dir, 0755);
- if (r < 0)
- return log_error_errno(r, "Failed to create runtime directory '%s': %m", runtime_dir);
+ return log_error_errno(r, "Failed to create runtime directory: %m");
- runtime_dir_destroy = strdup(runtime_dir);
- if (!runtime_dir_destroy)
- return log_oom();
- }
- /* When $RUNTIME_DIRECTORY is set the service manager created the directory for us and
- * will destroy it (or preserve it, per RuntimeDirectoryPreserve=) when the service stops. */
+ /* If a previous vmspawn instance was killed without cleanup (e.g. SIGKILL), the directory may
+ * already exist with stale contents. This is harmless: varlink's sockaddr_un_unlink() removes stale
+ * sockets before bind(), and other files (QEMU config, SSH keys) are created fresh. This matches
+ * nspawn's approach of not proactively cleaning stale runtime directories. */
log_debug("Using runtime directory: %s", runtime_dir);
if (arg_forward_journal) {
_cleanup_free_ char *listen_address = NULL;
-
- ChaseFlags chase_flags = CHASE_MKDIR_0755|CHASE_MUST_BE_DIRECTORY;
- if (endswith(arg_forward_journal, ".journal"))
- chase_flags |= CHASE_PARENT;
-
- _cleanup_close_ int journal_fd = -EBADF;
- r = chase(arg_forward_journal, /* root= */ NULL, chase_flags, /* ret_path= */ NULL, &journal_fd);
- if (r < 0)
- return log_error_errno(r, "Failed to create journal directory for '%s': %m", arg_forward_journal);
-
- r = chattr_fd(journal_fd, FS_NOCOW_FL, FS_NOCOW_FL);
- if (r < 0)
- log_debug_errno(r, "Failed to set NOCOW flag on journal directory for '%s', ignoring: %m", arg_forward_journal);
+ if (asprintf(&listen_address, "vsock:2:%u", child_cid) < 0)
+ return log_oom();
if (!GREEDY_REALLOC(children, n_children + 1))
return log_oom();
_cleanup_(fork_notify_terminate) PidRef child = PIDREF_NULL;
- r = start_systemd_journal_remote(unit, child_cid, sd_socket_activate, &listen_address, &child);
+ r = fork_journal_remote(
+ listen_address,
+ arg_forward_journal,
+ arg_forward_journal_max_use,
+ arg_forward_journal_keep_free,
+ arg_forward_journal_max_file_size,
+ arg_forward_journal_max_files,
+ &child);
if (r < 0)
return r;