From: Lennart Poettering Date: Wed, 17 Jul 2019 08:58:22 +0000 (+0200) Subject: copy: optionally check for SIGINT regularly, and abort operation safely X-Git-Tag: v243-rc1~99^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=85559592a653fedcc664f7500f0b8c49233b49db;p=thirdparty%2Fsystemd.git copy: optionally check for SIGINT regularly, and abort operation safely --- diff --git a/src/basic/copy.c b/src/basic/copy.c index 36ea7821f23..ca311e021e3 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -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; } diff --git a/src/basic/copy.h b/src/basic/copy.h index 51ea4d51eb3..906c6f70aec 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -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);