#include "shift-uid.h"
#include "signal-util.h"
#include "siphash24.h"
+#include "snapshot-util.h"
#include "socket-util.h"
#include "stat-util.h"
#include "stdio-util.h"
}
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_fdset_free_ FDSet *fds = NULL;
int r, ret = EXIT_SUCCESS;
struct ExposeArgs expose_args = {};
_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_(rm_rf_subvolume_and_freep) char *snapshot_dir = NULL;
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
_cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL;
}
if (arg_ephemeral) {
- _cleanup_free_ char *np = NULL;
-
r = chase_and_update(&arg_directory, 0);
if (r < 0)
goto finish;
- /* 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(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(
+ r = create_ephemeral_snapshot(
+ arg_directory,
arg_privileged ? RUNTIME_SCOPE_SYSTEM : RUNTIME_SCOPE_USER,
- np,
- LOCK_EX|LOCK_NB,
- arg_privileged ? &tree_global_lock : NULL,
- &tree_local_lock);
+ arg_read_only,
+ &tree_global_lock,
+ &tree_local_lock,
+ &snapshot_dir);
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;
}
- {
- 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);
+ arg_directory = strdup(snapshot_dir);
+ if (!arg_directory) {
+ log_oom();
goto finish;
}
- if (r < 0) {
- log_error_errno(r, "Failed to create snapshot %s from %s: %m", np, arg_directory);
- goto finish;
- }
-
- free_and_replace(arg_directory, np);
- remove_directory = true;
} else {
r = chase_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0);
if (r < 0)
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 (unlink(arg_image) < 0)
log_warning_errno(errno, "Can't remove image file '%s', ignoring: %m", arg_image);
--- /dev/null
+/* 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;
+}