mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-23 17:34:00 +03:00
Merge pull request #13091 from poettering/nspawn-copy
nspawn: allow nspawn's copy operation to be abortable via C-c
This commit is contained in:
commit
5f3626bb13
@ -1624,7 +1624,7 @@ int btrfs_subvol_snapshot_fd_full(
|
||||
} else if (r < 0)
|
||||
return r;
|
||||
|
||||
r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT, progress_path, progress_bytes, userdata);
|
||||
r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT|(FLAGS_SET(flags, BTRFS_SNAPSHOT_SIGINT) ? COPY_SIGINT : 0), progress_path, progress_bytes, userdata);
|
||||
if (r < 0)
|
||||
goto fallback_fail;
|
||||
|
||||
|
@ -34,6 +34,7 @@ typedef enum BtrfsSnapshotFlags {
|
||||
BTRFS_SNAPSHOT_QUOTA = 1 << 3,
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY = 1 << 4, /* If the destination doesn't support subvolumes, reflink/copy instead */
|
||||
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE = 1 << 5, /* When we can't create a subvolume, use the FS_IMMUTABLE attribute for indicating read-only */
|
||||
BTRFS_SNAPSHOT_SIGINT = 1 << 6, /* Check for SIGINT regularly, and return EINTR if seen */
|
||||
} BtrfsSnapshotFlags;
|
||||
|
||||
typedef enum BtrfsRemoveFlags {
|
||||
|
@ -86,6 +86,22 @@ static int fd_is_nonblock_pipe(int fd) {
|
||||
return FLAGS_SET(flags, O_NONBLOCK) ? FD_IS_NONBLOCKING_PIPE : FD_IS_BLOCKING_PIPE;
|
||||
}
|
||||
|
||||
static int sigint_pending(void) {
|
||||
sigset_t ss;
|
||||
|
||||
assert_se(sigemptyset(&ss) >= 0);
|
||||
assert_se(sigaddset(&ss, SIGINT) >= 0);
|
||||
|
||||
if (sigtimedwait(&ss, NULL, &(struct timespec) { 0, 0 }) < 0) {
|
||||
if (errno == EAGAIN)
|
||||
return false;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int copy_bytes_full(
|
||||
int fdf, int fdt,
|
||||
uint64_t max_bytes,
|
||||
@ -174,6 +190,14 @@ int copy_bytes_full(
|
||||
if (max_bytes <= 0)
|
||||
return 1; /* return > 0 if we hit the max_bytes limit */
|
||||
|
||||
if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
|
||||
r = sigint_pending();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (max_bytes != UINT64_MAX && m > max_bytes)
|
||||
m = max_bytes;
|
||||
|
||||
@ -559,6 +583,14 @@ static int fd_copy_directory(
|
||||
if (dot_or_dot_dot(de->d_name))
|
||||
continue;
|
||||
|
||||
if (FLAGS_SET(copy_flags, COPY_SIGINT)) {
|
||||
r = sigint_pending();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
|
||||
r = -errno;
|
||||
continue;
|
||||
@ -618,9 +650,10 @@ static int fd_copy_directory(
|
||||
else
|
||||
q = -EOPNOTSUPP;
|
||||
|
||||
if (q == -EINTR) /* Propagate SIGINT up instantly */
|
||||
return q;
|
||||
if (q == -EEXIST && (copy_flags & COPY_MERGE))
|
||||
q = 0;
|
||||
|
||||
if (q < 0)
|
||||
r = q;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ typedef enum CopyFlags {
|
||||
COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
|
||||
COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
|
||||
COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
|
||||
COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */
|
||||
} CopyFlags;
|
||||
|
||||
typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
|
||||
|
@ -4663,19 +4663,19 @@ static int initialize_rlimits(void) {
|
||||
}
|
||||
|
||||
static int run(int argc, char *argv[]) {
|
||||
bool secondary = false, remove_directory = false, remove_image = false,
|
||||
veth_created = false, remove_tmprootdir = false;
|
||||
_cleanup_close_ int master = -1;
|
||||
_cleanup_fdset_free_ FDSet *fds = NULL;
|
||||
int r, n_fd_passed, ret = EXIT_SUCCESS;
|
||||
char veth_name[IFNAMSIZ] = "";
|
||||
bool secondary = false, remove_directory = false, remove_image = false;
|
||||
pid_t pid = 0;
|
||||
union in_addr_union exposed = {};
|
||||
_cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
|
||||
bool veth_created = false, remove_tmprootdir = false;
|
||||
char tmprootdir[] = "/tmp/nspawn-root-XXXXXX";
|
||||
_cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
|
||||
_cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
|
||||
_cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
|
||||
pid_t pid = 0;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
@ -4753,12 +4753,9 @@ static int run(int argc, char *argv[]) {
|
||||
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. */
|
||||
/* 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, NULL, 0);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to determine whether directory %s is mount point: %m", arg_directory);
|
||||
@ -4779,21 +4776,27 @@ static int run(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = btrfs_subvol_snapshot(arg_directory, np,
|
||||
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
|
||||
BTRFS_SNAPSHOT_FALLBACK_COPY |
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
|
||||
BTRFS_SNAPSHOT_RECURSIVE |
|
||||
BTRFS_SNAPSHOT_QUOTA);
|
||||
{
|
||||
BLOCK_SIGNALS(SIGINT);
|
||||
r = btrfs_subvol_snapshot(arg_directory, 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) {
|
||||
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_symlinks_and_update(&arg_directory, arg_template ? CHASE_NONEXISTENT : 0);
|
||||
if (r < 0)
|
||||
@ -4814,17 +4817,24 @@ static int run(int argc, char *argv[]) {
|
||||
if (r < 0)
|
||||
goto finish;
|
||||
|
||||
r = btrfs_subvol_snapshot(arg_template, arg_directory,
|
||||
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
|
||||
BTRFS_SNAPSHOT_FALLBACK_COPY |
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
|
||||
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
|
||||
BTRFS_SNAPSHOT_RECURSIVE |
|
||||
BTRFS_SNAPSHOT_QUOTA);
|
||||
{
|
||||
BLOCK_SIGNALS(SIGINT);
|
||||
r = btrfs_subvol_snapshot(arg_template, arg_directory,
|
||||
(arg_read_only ? BTRFS_SNAPSHOT_READ_ONLY : 0) |
|
||||
BTRFS_SNAPSHOT_FALLBACK_COPY |
|
||||
BTRFS_SNAPSHOT_FALLBACK_DIRECTORY |
|
||||
BTRFS_SNAPSHOT_FALLBACK_IMMUTABLE |
|
||||
BTRFS_SNAPSHOT_RECURSIVE |
|
||||
BTRFS_SNAPSHOT_QUOTA |
|
||||
BTRFS_SNAPSHOT_SIGINT);
|
||||
}
|
||||
if (r == -EEXIST)
|
||||
log_full(arg_quiet ? LOG_DEBUG : LOG_INFO,
|
||||
"Directory %s already exists, not populating from template %s.", arg_directory, arg_template);
|
||||
else if (r < 0) {
|
||||
else if (r == -EINTR) {
|
||||
log_error_errno(r, "Interrupted while copying file system tree to %s, removed again.", arg_directory);
|
||||
goto finish;
|
||||
} else if (r < 0) {
|
||||
log_error_errno(r, "Couldn't create snapshot %s from %s: %m", arg_directory, arg_template);
|
||||
goto finish;
|
||||
} else
|
||||
@ -4886,14 +4896,20 @@ static int run(int argc, char *argv[]) {
|
||||
goto finish;
|
||||
}
|
||||
|
||||
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, FS_NOCOW_FL, COPY_REFLINK|COPY_CRTIME);
|
||||
{
|
||||
BLOCK_SIGNALS(SIGINT);
|
||||
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, FS_NOCOW_FL, COPY_REFLINK|COPY_CRTIME|COPY_SIGINT);
|
||||
}
|
||||
if (r == -EINTR) {
|
||||
log_error_errno(r, "Interrupted while copying image file to %s, removed again.", np);
|
||||
goto finish;
|
||||
}
|
||||
if (r < 0) {
|
||||
r = log_error_errno(r, "Failed to copy image file: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
free_and_replace(arg_image, np);
|
||||
|
||||
remove_image = true;
|
||||
} else {
|
||||
r = image_path_lock(arg_image, (arg_read_only ? LOCK_SH : LOCK_EX) | LOCK_NB, &tree_global_lock, &tree_local_lock);
|
||||
|
Loading…
Reference in New Issue
Block a user