mirror of
https://github.com/systemd/systemd
synced 2026-03-14 17:14:49 +01:00
Compare commits
3 Commits
503a788332
...
5a35a6d9d4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a35a6d9d4 | ||
|
|
6e67fc2938 | ||
|
|
96dd2df514 |
@ -125,6 +125,17 @@
|
|||||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><option>-x</option></term>
|
||||||
|
<term><option>--ephemeral</option></term>
|
||||||
|
|
||||||
|
<listitem><para>If specified, the VM is run with a temporary snapshot of its file system that is removed
|
||||||
|
immediately when the VM terminates. Only works with <option>--image=</option> currently.
|
||||||
|
|
||||||
|
Note that <option>--ephemeral</option> will not work with <option>--extra-drive=</option>.</para>
|
||||||
|
|
||||||
|
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||||
|
</varlistentry>
|
||||||
</variablelist>
|
</variablelist>
|
||||||
</refsect2>
|
</refsect2>
|
||||||
|
|
||||||
|
|||||||
@ -107,6 +107,7 @@
|
|||||||
#include "shift-uid.h"
|
#include "shift-uid.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
#include "siphash24.h"
|
#include "siphash24.h"
|
||||||
|
#include "snapshot-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
@ -5915,7 +5916,7 @@ static int do_cleanup(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int run(int argc, char *argv[]) {
|
static int run(int argc, char *argv[]) {
|
||||||
bool remove_directory = false, remove_image = false, veth_created = false;
|
bool remove_image = false, veth_created = false;
|
||||||
_cleanup_close_ int master = -EBADF, userns_fd = -EBADF, mount_fd = -EBADF;
|
_cleanup_close_ int master = -EBADF, userns_fd = -EBADF, mount_fd = -EBADF;
|
||||||
_cleanup_fdset_free_ FDSet *fds = NULL;
|
_cleanup_fdset_free_ FDSet *fds = NULL;
|
||||||
int r, ret = EXIT_SUCCESS;
|
int r, ret = EXIT_SUCCESS;
|
||||||
@ -5923,6 +5924,7 @@ static int run(int argc, char *argv[]) {
|
|||||||
struct ExposeArgs expose_args = {};
|
struct ExposeArgs expose_args = {};
|
||||||
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
||||||
_cleanup_(rmdir_and_freep) char *rootdir = NULL;
|
_cleanup_(rmdir_and_freep) char *rootdir = NULL;
|
||||||
|
_cleanup_(rm_rf_subvolume_and_freep) char *snapshot_dir = NULL;
|
||||||
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
|
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
|
||||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||||
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
|
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
|
||||||
@ -6064,63 +6066,27 @@ static int run(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (arg_ephemeral) {
|
if (arg_ephemeral) {
|
||||||
_cleanup_free_ char *np = NULL;
|
|
||||||
|
|
||||||
r = chase_and_update(&arg_directory, 0);
|
r = chase_and_update(&arg_directory, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto finish;
|
goto finish;
|
||||||
|
|
||||||
/* If the specified path is a mount point we generate the new snapshot immediately
|
r = create_ephemeral_snapshot(
|
||||||
* inside it under a random name. However if the specified is not a mount point we
|
arg_directory,
|
||||||
* create the new snapshot in the parent directory, just next to it. */
|
|
||||||
r = path_is_mount_point(arg_directory);
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
if (r > 0)
|
|
||||||
r = tempfn_random_child(arg_directory, "machine.", &np);
|
|
||||||
else
|
|
||||||
r = tempfn_random(arg_directory, "machine.", &np);
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to generate name for directory snapshot: %m");
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We take an exclusive lock on this image, since it's our private, ephemeral copy
|
|
||||||
* only owned by us and no one else. */
|
|
||||||
r = image_path_lock(
|
|
||||||
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
|
||||||
np,
|
arg_read_only,
|
||||||
LOCK_EX|LOCK_NB,
|
&tree_global_lock,
|
||||||
arg_privileged ? &tree_global_lock : NULL,
|
&tree_local_lock,
|
||||||
&tree_local_lock);
|
&snapshot_dir);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to lock %s: %m", np);
|
log_error_errno(r, "Failed to create ephemeral snapshot: %m");
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
r = free_and_strdup(&arg_directory, snapshot_dir);
|
||||||
BLOCK_SIGNALS(SIGINT);
|
|
||||||
r = btrfs_subvol_snapshot_at(AT_FDCWD, arg_directory, AT_FDCWD, np,
|
|
||||||
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
|
|
||||||
BTRFS_SNAPSHOT_FALLBACK_COPY |
|
|
||||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
|
|
||||||
BTRFS_SNAPSHOT_RECURSIVE |
|
|
||||||
BTRFS_SNAPSHOT_QUOTA |
|
|
||||||
BTRFS_SNAPSHOT_SIGINT);
|
|
||||||
}
|
|
||||||
if (r == -EINTR) {
|
|
||||||
log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", np);
|
|
||||||
goto finish;
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
|
log_oom();
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_and_replace(arg_directory, np);
|
|
||||||
remove_directory = true;
|
|
||||||
} else {
|
} else {
|
||||||
r = chase_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0);
|
r = chase_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -6471,14 +6437,6 @@ finish:
|
|||||||
|
|
||||||
pager_close();
|
pager_close();
|
||||||
|
|
||||||
if (remove_directory && arg_directory) {
|
|
||||||
int k;
|
|
||||||
|
|
||||||
k = rm_rf(arg_directory, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME);
|
|
||||||
if (k < 0)
|
|
||||||
log_warning_errno(k, "Cannot remove '%s', ignoring: %m", arg_directory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (remove_image && arg_image) {
|
if (remove_image && arg_image) {
|
||||||
if (unlink(arg_image) < 0)
|
if (unlink(arg_image) < 0)
|
||||||
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
|
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
|
||||||
|
|||||||
@ -177,6 +177,7 @@ shared_sources = files(
|
|||||||
'sleep-config.c',
|
'sleep-config.c',
|
||||||
'smack-util.c',
|
'smack-util.c',
|
||||||
'smbios11.c',
|
'smbios11.c',
|
||||||
|
'snapshot-util.c',
|
||||||
'socket-label.c',
|
'socket-label.c',
|
||||||
'socket-netlink.c',
|
'socket-netlink.c',
|
||||||
'specifier.c',
|
'specifier.c',
|
||||||
|
|||||||
65
src/shared/snapshot-util.c
Normal file
65
src/shared/snapshot-util.c
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include <sys/file.h>
|
||||||
|
|
||||||
|
#include "alloc-util.h"
|
||||||
|
#include "btrfs-util.h"
|
||||||
|
#include "discover-image.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "mountpoint-util.h"
|
||||||
|
#include "snapshot-util.h"
|
||||||
|
#include "signal-util.h"
|
||||||
|
#include "tmpfile-util.h"
|
||||||
|
|
||||||
|
int create_ephemeral_snapshot(
|
||||||
|
const char *directory,
|
||||||
|
RuntimeScope scope,
|
||||||
|
bool read_only,
|
||||||
|
LockFile *tree_global_lock,
|
||||||
|
LockFile *tree_local_lock,
|
||||||
|
char **ret_new_path) {
|
||||||
|
|
||||||
|
_cleanup_free_ char *np = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* If the specified path is a mount point we generate the new snapshot immediately
|
||||||
|
* inside it under a random name. However if the specified is not a mount point we
|
||||||
|
* create the new snapshot in the parent directory, just next to it. */
|
||||||
|
r = path_is_mount_point(directory);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to determine whether directory %s is mount point: %m", directory);
|
||||||
|
if (r > 0)
|
||||||
|
r = tempfn_random_child(directory, "snapshot.", &np);
|
||||||
|
else
|
||||||
|
r = tempfn_random(directory, "snapshot.", &np);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to generate name for directory snapshot: %m");
|
||||||
|
|
||||||
|
/* We take an exclusive lock on this image, since it's our private, ephemeral copy
|
||||||
|
* only owned by us and no one else. */
|
||||||
|
r = image_path_lock(
|
||||||
|
scope,
|
||||||
|
np,
|
||||||
|
LOCK_EX|LOCK_NB,
|
||||||
|
scope == RUNTIME_SCOPE_SYSTEM ? tree_global_lock : NULL,
|
||||||
|
tree_local_lock);
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to lock %s: %m", np);
|
||||||
|
|
||||||
|
{
|
||||||
|
BLOCK_SIGNALS(SIGINT);
|
||||||
|
r = btrfs_subvol_snapshot_at(AT_FDCWD, directory, AT_FDCWD, np,
|
||||||
|
(read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
|
||||||
|
BTRFS_SNAPSHOT_FALLBACK_COPY |
|
||||||
|
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
|
||||||
|
BTRFS_SNAPSHOT_RECURSIVE |
|
||||||
|
BTRFS_SNAPSHOT_QUOTA |
|
||||||
|
BTRFS_SNAPSHOT_SIGINT);
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to create snapshot %s from %s: %m", np, directory);
|
||||||
|
|
||||||
|
*ret_new_path = TAKE_PTR(np);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
21
src/shared/snapshot-util.h
Normal file
21
src/shared/snapshot-util.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "runtime-scope.h"
|
||||||
|
|
||||||
|
/* create_ephemeral_snapshot - create a snapshot of the given directory.
|
||||||
|
*
|
||||||
|
* It will use a btrfs snapshot when available with fallback to traditional dir copy. It will set the global
|
||||||
|
* and local lock files based on the passed runtime scope. On success the new directory path is returned via
|
||||||
|
* `ret_new_path`.
|
||||||
|
*
|
||||||
|
* The caller is responsible for the cleanup of the directory, using `_cleanup_(rm_rf_subvolume_and_freep)`
|
||||||
|
* is recommended.
|
||||||
|
*/
|
||||||
|
int create_ephemeral_snapshot(
|
||||||
|
const char *directory,
|
||||||
|
RuntimeScope scope,
|
||||||
|
bool read_only,
|
||||||
|
LockFile *tree_global_lock,
|
||||||
|
LockFile *tree_local_lock,
|
||||||
|
char **ret_new_path);
|
||||||
@ -35,6 +35,7 @@ typedef enum SettingsMask {
|
|||||||
SETTING_START_MODE = UINT64_C(1) << 0,
|
SETTING_START_MODE = UINT64_C(1) << 0,
|
||||||
SETTING_MACHINE_ID = UINT64_C(1) << 6,
|
SETTING_MACHINE_ID = UINT64_C(1) << 6,
|
||||||
SETTING_BIND_MOUNTS = UINT64_C(1) << 11,
|
SETTING_BIND_MOUNTS = UINT64_C(1) << 11,
|
||||||
|
SETTING_EPHEMERAL = UINT64_C(1) << 24,
|
||||||
SETTING_DIRECTORY = UINT64_C(1) << 26,
|
SETTING_DIRECTORY = UINT64_C(1) << 26,
|
||||||
SETTING_CREDENTIALS = UINT64_C(1) << 30,
|
SETTING_CREDENTIALS = UINT64_C(1) << 30,
|
||||||
_SETTING_FORCE_ENUM_WIDTH = UINT64_MAX
|
_SETTING_FORCE_ENUM_WIDTH = UINT64_MAX
|
||||||
|
|||||||
@ -62,6 +62,7 @@
|
|||||||
#include "random-util.h"
|
#include "random-util.h"
|
||||||
#include "rm-rf.h"
|
#include "rm-rf.h"
|
||||||
#include "signal-util.h"
|
#include "signal-util.h"
|
||||||
|
#include "snapshot-util.h"
|
||||||
#include "socket-util.h"
|
#include "socket-util.h"
|
||||||
#include "stat-util.h"
|
#include "stat-util.h"
|
||||||
#include "stdio-util.h"
|
#include "stdio-util.h"
|
||||||
@ -145,6 +146,7 @@ static char **arg_bind_user = NULL;
|
|||||||
static char *arg_bind_user_shell = NULL;
|
static char *arg_bind_user_shell = NULL;
|
||||||
static bool arg_bind_user_shell_copy = false;
|
static bool arg_bind_user_shell_copy = false;
|
||||||
static char **arg_bind_user_groups = NULL;
|
static char **arg_bind_user_groups = NULL;
|
||||||
|
static bool arg_ephemeral = false;
|
||||||
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
static RuntimeScope arg_runtime_scope = _RUNTIME_SCOPE_INVALID;
|
||||||
|
|
||||||
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
|
STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
|
||||||
@ -190,6 +192,7 @@ static int help(void) {
|
|||||||
" --system Interact with system manager\n"
|
" --system Interact with system manager\n"
|
||||||
"\n%3$sImage:%4$s\n"
|
"\n%3$sImage:%4$s\n"
|
||||||
" -D --directory=PATH Root directory for the VM\n"
|
" -D --directory=PATH Root directory for the VM\n"
|
||||||
|
" -x --ephemeral Run VM with snapshot of the disk or directory\n"
|
||||||
" -i --image=FILE|DEVICE Root file system disk image or device for the VM\n"
|
" -i --image=FILE|DEVICE Root file system disk image or device for the VM\n"
|
||||||
" --image-format=FORMAT Specify disk image format (raw, qcow2; default: raw)\n"
|
" --image-format=FORMAT Specify disk image format (raw, qcow2; default: raw)\n"
|
||||||
"\n%3$sHost Configuration:%4$s\n"
|
"\n%3$sHost Configuration:%4$s\n"
|
||||||
@ -327,6 +330,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
|
||||||
{ "image", required_argument, NULL, 'i' },
|
{ "image", required_argument, NULL, 'i' },
|
||||||
{ "image-format", required_argument, NULL, ARG_IMAGE_FORMAT },
|
{ "image-format", required_argument, NULL, ARG_IMAGE_FORMAT },
|
||||||
|
{ "ephemeral", no_argument, NULL, 'x' },
|
||||||
{ "directory", required_argument, NULL, 'D' },
|
{ "directory", required_argument, NULL, 'D' },
|
||||||
{ "machine", required_argument, NULL, 'M' },
|
{ "machine", required_argument, NULL, 'M' },
|
||||||
{ "slice", required_argument, NULL, 'S' },
|
{ "slice", required_argument, NULL, 'S' },
|
||||||
@ -382,7 +386,7 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
assert(argv);
|
assert(argv);
|
||||||
|
|
||||||
optind = 0;
|
optind = 0;
|
||||||
while ((c = getopt_long(argc, argv, "+hD:i:M:nqs:G:S:", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "+hD:i:xM:nqs:G:S:", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'h':
|
case 'h':
|
||||||
return help();
|
return help();
|
||||||
@ -429,6 +433,10 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
arg_ephemeral = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case ARG_NO_PAGER:
|
case ARG_NO_PAGER:
|
||||||
arg_pager_flags |= PAGER_DISABLE;
|
arg_pager_flags |= PAGER_DISABLE;
|
||||||
break;
|
break;
|
||||||
@ -794,6 +802,9 @@ static int parse_argv(int argc, char *argv[]) {
|
|||||||
if (!strv_isempty(arg_bind_user_groups) && strv_isempty(arg_bind_user))
|
if (!strv_isempty(arg_bind_user_groups) && strv_isempty(arg_bind_user))
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --bind-user-group= without --bind-user=");
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --bind-user-group= without --bind-user=");
|
||||||
|
|
||||||
|
if (arg_ephemeral && arg_extra_drives.n_drives > 0)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --ephemeral with --extra-drive=");
|
||||||
|
|
||||||
if (argc > optind) {
|
if (argc > optind) {
|
||||||
arg_kernel_cmdline_extra = strv_copy(argv + optind);
|
arg_kernel_cmdline_extra = strv_copy(argv + optind);
|
||||||
if (!arg_kernel_cmdline_extra)
|
if (!arg_kernel_cmdline_extra)
|
||||||
@ -1843,6 +1854,8 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
|
_cleanup_(ovmf_config_freep) OvmfConfig *ovmf_config = NULL;
|
||||||
_cleanup_free_ char *qemu_binary = NULL, *mem = NULL, *kernel = NULL;
|
_cleanup_free_ char *qemu_binary = NULL, *mem = NULL, *kernel = NULL;
|
||||||
_cleanup_(rm_rf_physical_and_freep) char *ssh_private_key_path = NULL, *ssh_public_key_path = NULL;
|
_cleanup_(rm_rf_physical_and_freep) char *ssh_private_key_path = NULL, *ssh_public_key_path = NULL;
|
||||||
|
_cleanup_(rm_rf_subvolume_and_freep) char *snapshot_directory = NULL;
|
||||||
|
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
||||||
_cleanup_close_ int notify_sock_fd = -EBADF;
|
_cleanup_close_ int notify_sock_fd = -EBADF;
|
||||||
_cleanup_strv_free_ char **cmdline = NULL;
|
_cleanup_strv_free_ char **cmdline = NULL;
|
||||||
_cleanup_free_ int *pass_fds = NULL;
|
_cleanup_free_ int *pass_fds = NULL;
|
||||||
@ -2319,7 +2332,8 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
if (!escaped_image)
|
if (!escaped_image)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
if (strv_extendf(&cmdline, "if=none,id=vmspawn,file=%s,format=%s,discard=%s", escaped_image, image_format_to_string(arg_image_format), on_off(arg_discard_disk)) < 0)
|
if (strv_extendf(&cmdline, "if=none,id=vmspawn,file=%s,format=%s,discard=%s,snapshot=%s",
|
||||||
|
escaped_image, image_format_to_string(arg_image_format), on_off(arg_discard_disk), on_off(arg_ephemeral)) < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
_cleanup_free_ char *image_fn = NULL;
|
_cleanup_free_ char *image_fn = NULL;
|
||||||
@ -2366,6 +2380,21 @@ static int run_virtual_machine(int kvm_device_fd, int vhost_device_fd) {
|
|||||||
if (!GREEDY_REALLOC(children, n_children + 1))
|
if (!GREEDY_REALLOC(children, n_children + 1))
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
if (arg_ephemeral) {
|
||||||
|
r = create_ephemeral_snapshot(arg_directory,
|
||||||
|
arg_runtime_scope,
|
||||||
|
/* read-only */ false,
|
||||||
|
&tree_global_lock,
|
||||||
|
&tree_local_lock,
|
||||||
|
&snapshot_directory);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
arg_directory = strdup(snapshot_directory);
|
||||||
|
if (!arg_directory)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
r = start_virtiofsd(
|
r = start_virtiofsd(
|
||||||
unit,
|
unit,
|
||||||
arg_directory,
|
arg_directory,
|
||||||
@ -3065,6 +3094,11 @@ static int determine_names(void) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to extract file name from '%s': %m", arg_directory);
|
return log_error_errno(r, "Failed to extract file name from '%s': %m", arg_directory);
|
||||||
}
|
}
|
||||||
|
/* Add a random suffix when this is an ephemeral machine, so that we can run many
|
||||||
|
* instances at once without manually having to specify -M each time. */
|
||||||
|
if (arg_ephemeral)
|
||||||
|
if (strextendf(&arg_machine, "-%016" PRIx64, random_u64()) < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
hostname_cleanup(arg_machine);
|
hostname_cleanup(arg_machine);
|
||||||
if (!hostname_is_valid(arg_machine, 0))
|
if (!hostname_is_valid(arg_machine, 0))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user