Use select() in dd(1)

Avoid blocking in a call to splice() when no input is available.
We can now break out of dd using ^C even if the input is coming from
/dev/stdin.

Use tabs instead of spaces.
This commit is contained in:
sin 2014-06-11 12:57:10 +01:00
parent c94dfdc99d
commit 0ca8e52bc1

94
dd.c
View File

@ -17,6 +17,8 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/vfs.h> #include <sys/vfs.h>
#include <time.h> #include <time.h>
@ -135,48 +137,60 @@ prepare_copy(struct dd_config *ddc, int *ifd, int *ofd)
static int static int
copy_splice(struct dd_config *ddc) 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;
if (prepare_copy(ddc, &ifd, &ofd) < 0) fd_set rfd, wfd;
return -1;
if (pipe(p) < 0) { if (prepare_copy(ddc, &ifd, &ofd) < 0)
ddc->saved_errno = errno; return -1;
close(ifd); close(ofd); if (pipe(p) < 0) {
close(p[0]); close(p[1]); ddc->saved_errno = errno;
return -1; close(ifd); close(ofd);
} close(p[0]); close(p[1]);
return -1;
}
#ifdef F_SETPIPE_SZ #ifdef F_SETPIPE_SZ
for (n = 29; n >= 20; --n) { for (n = 29; n >= 20; --n) {
if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1) if (fcntl(p[0], F_SETPIPE_SZ, 1<<n) != -1)
break; break;
} }
#endif #endif
n = ddc->bs; n = ddc->bs;
for (;ddc->b_out != ddc->count && !sigint;) { for (;ddc->b_out != ddc->count && !sigint;) {
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); FD_ZERO(&rfd);
if (r <= 0) { FD_ZERO(&wfd);
ddc->saved_errno = errno; FD_SET(ifd, &rfd);
break; FD_SET(ofd, &wfd);
} if (select(ifd > ofd ? ifd + 1 : ofd + 1, &rfd, &wfd, NULL, NULL) < 0) {
++ddc->rec_in; ddc->saved_errno = errno;
r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE); break;
if (r <= 0) { }
ddc->saved_errno = errno; if (FD_ISSET(ifd, &rfd) == 1 && FD_ISSET(ofd, &wfd) == 1) {
break; r = splice(ifd, NULL, p[1], NULL, n, SPLICE_F_MORE);
} if (r <= 0) {
ddc->b_out += r; ddc->saved_errno = errno;
++ddc->rec_out; break;
} }
close(ifd); ++ddc->rec_in;
close(ofd); r = splice(p[0], NULL, ofd, NULL, r, SPLICE_F_MORE);
close(p[0]); if (r <= 0) {
close(p[1]); ddc->saved_errno = errno;
if (r < 0) break;
return -1; }
return 0; ddc->b_out += r;
++ddc->rec_out;
}
}
close(ifd);
close(ofd);
close(p[0]);
close(p[1]);
if (r < 0)
return -1;
return 0;
} }
static int static int