dd: Use sigaction(2) to obviate select(2)

By setting the SIGINT handler with sigaction(2), automatic retries of
the splice(2) syscall can be disabled by not setting SA_RESTART. This
makes it possible to use Ctrl+C even if the "if" operand refers to the
controlling terminal. The SIGINT message has also been moved outside
the signal handler since fprintf(3) is not an async-signal-safe
function.
This commit is contained in:
Eric Pruitt 2017-10-10 16:27:27 +01:00 committed by sin
parent fae9ca81a2
commit 55795531f0
1 changed files with 32 additions and 29 deletions

61
dd.c
View File

@ -8,7 +8,6 @@
*/ */
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/select.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
@ -38,6 +37,15 @@ struct dd_config {
static int sigint = 0; static int sigint = 0;
static void
sig_int(int unused_1, siginfo_t *unused_2, void *unused_3)
{
(void) unused_1;
(void) unused_2;
(void) unused_3;
sigint = 1;
}
static int static int
prepare_copy(struct dd_config *ddc, int *ifd, int *ofd) prepare_copy(struct dd_config *ddc, int *ifd, int *ofd)
{ {
@ -147,7 +155,6 @@ copy_splice(struct dd_config *ddc)
int ifd, ofd, p[2] = {-1, -1}; int ifd, ofd, p[2] = {-1, -1};
ssize_t r = 0; ssize_t r = 0;
size_t n = 0; size_t n = 0;
fd_set rfd, wfd;
if (prepare_copy(ddc, &ifd, &ofd) < 0) if (prepare_copy(ddc, &ifd, &ofd) < 0)
return -1; return -1;
@ -165,27 +172,24 @@ copy_splice(struct dd_config *ddc)
#endif #endif
n = ddc->bs; n = ddc->bs;
for (;ddc->b_out != ddc->count && !sigint;) { for (;ddc->b_out != ddc->count && !sigint;) {
FD_ZERO(&rfd);
FD_ZERO(&wfd);
FD_SET(ifd, &rfd);
FD_SET(ofd, &wfd);
r = select(ifd > ofd ? ifd + 1 : ofd + 1, &rfd, &wfd, NULL, NULL);
if (r < 0) if (r < 0)
break; break;
if (FD_ISSET(ifd, &rfd) == 1 && FD_ISSET(ofd, &wfd) == 1) { if (n > ddc->count - ddc->b_out)
if (n > ddc->count - ddc->b_out) n = ddc->count - ddc->b_out;
n = ddc->count - ddc->b_out; r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);
r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE); if (r <= 0)
if (r <= 0) break;
break; ++ddc->rec_in;
++ddc->rec_in; r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);
r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE); if (r <= 0)
if (r <= 0) break;
break; ddc->b_out += r;
ddc->b_out += r; ++ddc->rec_out;
++ddc->rec_out;
}
} }
if (sigint)
fprintf(stderr, "SIGINT! Aborting ...\n");
close(ifd); close(ifd);
close(ofd); close(ofd);
close(p[0]); close(p[0]);
@ -226,14 +230,6 @@ print_stat(const struct dd_config *ddc)
((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start)); ((double)(ddc->b_out/(1<<20)))/(ddc->t_end - ddc->t_start));
} }
static void
sig_int(int unused)
{
(void) unused;
fprintf(stderr, "SIGINT! Aborting ...\n");
sigint = 1;
}
static void static void
usage(void) usage(void)
{ {
@ -248,6 +244,7 @@ main(int argc, char *argv[])
int i = 0; int i = 0;
char buf[1024]; char buf[1024];
struct dd_config config; struct dd_config config;
struct sigaction sa;
argv0 = argv[0]; argv0 = argv[0];
memset(&config, 0, sizeof(config)); memset(&config, 0, sizeof(config));
@ -286,7 +283,13 @@ main(int argc, char *argv[])
} }
signal(SIGPIPE, SIG_IGN); signal(SIGPIPE, SIG_IGN);
signal(SIGINT, sig_int);
sa.sa_flags = SA_SIGINFO;
sigemptyset(&sa.sa_mask);
sa.sa_sigaction = sig_int;
if (sigaction(SIGINT, &sa, NULL) == -1)
weprintf("sigaction");
if (copy(&config) < 0) if (copy(&config) < 0)
weprintf("copy:"); weprintf("copy:");