diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-03-09 22:45:08 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2018-05-24 17:01:57 +0200 |
commit | 4960ce43ff8c42a8c92219d88cbcdb82ae7a1ec0 (patch) | |
tree | aa5bd18fac50f61167452c34057d635c8d793113 /src/test/test-fd-util.c | |
parent | cdc0f9be925c79f52452938f39013062325da27a (diff) | |
download | systemd-4960ce43ff8c42a8c92219d88cbcdb82ae7a1ec0.tar.gz |
fd-util: add new helper call fd_duplicate_data_fd()
This call creates an fd from another fd containing the same data.
Specifically, repeated read() on the returned fd should return the same
data as the original fd. This call is useful when we want to copy data
out of disk images and suchlike, and want to be pass fds with the data
around without having to keep the disk image continously mounted.
The implementation tries to be somewhat smart and tries to prefer
memfds/pipes over files in /tmp or /var/tmp based on the size of the
data, but has appropropriate fallbacks in place.
Diffstat (limited to 'src/test/test-fd-util.c')
-rw-r--r-- | src/test/test-fd-util.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/src/test/test-fd-util.c b/src/test/test-fd-util.c index 432fa5d403..fc3c463385 100644 --- a/src/test/test-fd-util.c +++ b/src/test/test-fd-util.c @@ -228,6 +228,93 @@ static void test_rearrange_stdio(void) { } } +static void assert_equal_fd(int fd1, int fd2) { + + for (;;) { + uint8_t a[4096], b[4096]; + ssize_t x, y; + + x = read(fd1, a, sizeof(a)); + assert(x >= 0); + + y = read(fd2, b, sizeof(b)); + assert(y >= 0); + + assert(x == y); + + if (x == 0) + break; + + assert(memcmp(a, b, x) == 0); + } +} + +static void test_fd_duplicate_data_fd(void) { + _cleanup_close_ int fd1 = -1, fd2 = -1; + _cleanup_(close_pairp) int sfd[2] = { -1, -1 }; + _cleanup_(sigkill_waitp) pid_t pid = -1; + uint64_t i, j; + int r; + + fd1 = open("/etc/fstab", O_RDONLY|O_CLOEXEC); + if (fd1 >= 0) { + + fd2 = fd_duplicate_data_fd(fd1); + assert_se(fd2 >= 0); + + assert_se(lseek(fd1, 0, SEEK_SET) == 0); + assert_equal_fd(fd1, fd2); + } + + fd1 = safe_close(fd1); + fd2 = safe_close(fd2); + + fd1 = acquire_data_fd("hallo", 6, 0); + assert_se(fd1 >= 0); + + fd2 = fd_duplicate_data_fd(fd1); + assert_se(fd2 >= 0); + + safe_close(fd1); + fd1 = acquire_data_fd("hallo", 6, 0); + assert_se(fd1 >= 0); + + assert_equal_fd(fd1, fd2); + + fd1 = safe_close(fd1); + fd2 = safe_close(fd2); + + assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, sfd) >= 0); + + r = safe_fork("(sd-pipe)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid); + assert_se(r >= 0); + + if (r == 0) { + /* child */ + + sfd[0] = safe_close(sfd[0]); + + for (i = 0; i < 1536*1024 / sizeof(uint64_t); i++) + assert_se(write(sfd[1], &i, sizeof(i)) == sizeof(i)); + + sfd[1] = safe_close(sfd[1]); + + _exit(EXIT_SUCCESS); + } + + sfd[1] = safe_close(sfd[1]); + + fd2 = fd_duplicate_data_fd(sfd[0]); + assert_se(fd2 >= 0); + + for (i = 0; i < 1536*1024 / sizeof(uint64_t); i++) { + assert_se(read(fd2, &j, sizeof(j)) == sizeof(j)); + assert_se(i == j); + } + + assert_se(read(fd2, &j, sizeof(j)) == 0); +} + int main(int argc, char *argv[]) { test_close_many(); test_close_nointr(); @@ -236,6 +323,7 @@ int main(int argc, char *argv[]) { test_acquire_data_fd(); test_fd_move_above_stdio(); test_rearrange_stdio(); + test_fd_duplicate_data_fd(); return 0; } |