7#include <sys/inotify.h>
11static int copying(
void) {
12 int failed = 0, p[2] = {-1, -1}, file = -1;
13 const size_t page = sysconf(_SC_PAGESIZE);
14 char* source = MAP_FAILED;
17 source = mmap(NULL, 2 * page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
18 CHECK(source != MAP_FAILED);
19 memcpy(source,
"abcdefgh", 8);
20 struct iovec vectors[] = {{source, 3}, {source + 3, 5}};
21 CHECK(vmsplice(p[1], vectors, 2, SPLICE_F_MORE | SPLICE_F_MOVE) == 8);
22 memset(source,
'z', 8);
23 CHECK(!munmap(source, 2 * page));
25 struct iovec destinations[] = {{output, 3}, {output + 3, 5}};
26 CHECK(vmsplice(p[0], destinations, 2, SPLICE_F_GIFT) == 8 && !memcmp(output,
"abcdefgh", 8));
27 CHECK(vmsplice(p[0], destinations, 2, SPLICE_F_NONBLOCK) == -1 && errno == EAGAIN);
28 CHECK(vmsplice(p[1], NULL, 0, 0) == 0);
29 CHECK((file = pt_file(0, 0)) >= 0);
30 CHECK(vmsplice(file, NULL, 0, 0) == 0);
31 CHECK(vmsplice(file, destinations, 2, 0) == -1 && errno == EBADF);
32 CHECK(vmsplice(-1, NULL, 0, 0) == -1 && errno == EBADF);
35 CHECK(vmsplice(p[0], destinations, 2, 0) == 0);
39 if (source != MAP_FAILED)
40 munmap(source, 2 * page);
47static int faults_and_limits(
void) {
48 int failed = 0, p[2] = {-1, -1};
49 const size_t page = sysconf(_SC_PAGESIZE);
50 void* denied = MAP_FAILED;
51 char first[3] = {0}, tail[5] = {0}, large[PT_CAPACITY + 7];
53 denied = mmap(NULL, page, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
54 CHECK(denied != MAP_FAILED);
55 struct iovec bad = {denied, 8};
56 CHECK(vmsplice(p[1], &bad, 1, 0) == -1 && errno == EFAULT);
57 CHECK(vmsplice(p[1], denied, 1, 0) == -1 && errno == EFAULT);
58 CHECK(vmsplice(p[1], denied, 1025, 0) == -1 && errno == EINVAL);
59 struct iovec overflow = {first, SIZE_MAX};
60 CHECK(vmsplice(p[1], &overflow, 1, 0) == -1 && errno == EINVAL);
61 struct iovec incoming[] = {{
"abc", 3}, {denied, 5}};
62 CHECK(vmsplice(p[1], incoming, 2, 0) == 3);
63 CHECK(read(p[0], first, 3) == 3 && !memcmp(first,
"abc", 3));
64 CHECK(write(p[1],
"abcdefgh", 8) == 8);
65 CHECK(vmsplice(p[0], &bad, 1, 0) == -1 && errno == EFAULT);
66 struct iovec outgoing[] = {{first, 3}, {denied, 5}};
67 CHECK(vmsplice(p[0], outgoing, 2, 0) == 3 && !memcmp(first,
"abc", 3));
68 struct iovec retry = {tail, 5};
69 CHECK(vmsplice(p[0], &retry, 1, 0) == 5 && !memcmp(tail,
"defgh", 5));
70 struct iovec empty_first[] = {{denied, 0}, {
"abc", 3}};
71 CHECK(vmsplice(p[1], empty_first, 2, 0) == 3);
72 CHECK(read(p[0], first, 3) == 3 && !memcmp(first,
"abc", 3));
73 for (
size_t n = 0; n <
sizeof(large); ++n)
74 large[n] = pt_pattern(n, 61);
75 struct iovec bounded = {large,
sizeof(large)};
76 ssize_t amount = vmsplice(p[1], &bounded, 1, 0);
77 CHECK(amount > 0 && amount <= PT_CAPACITY && !pt_read(p[0], amount, 0, 61));
78 CHECK(vmsplice(p[1], &retry, 1, 0x80000000U) == -1 && errno == EINVAL);
79 CHECK(vmsplice(p[1], &retry, 1, SPLICE_F_GIFT) == -1 && errno == EINVAL);
81 if (denied != MAP_FAILED)
89static int aligned_gift(
void) {
90 int failed = 0, p[2] = {-1, -1};
91 const size_t page = sysconf(_SC_PAGESIZE);
92 unsigned char* memory = MAP_FAILED;
93 CHECK(!pipe(p) && page == PT_CAPACITY);
94 memory = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
95 CHECK(memory != MAP_FAILED);
96 for (
size_t n = 0; n < page; ++n)
97 memory[n] = pt_pattern(n, 79);
98 struct iovec vector = {memory, page};
99 CHECK(vmsplice(p[1], &vector, 1, SPLICE_F_GIFT) == (ssize_t)page);
101 CHECK(memory[0] == pt_pattern(0, 79) && memory[page - 1] == pt_pattern(page - 1, 79));
102 CHECK(!pt_read(p[0], page, 0, 79));
104 if (memory != MAP_FAILED)
105 munmap(memory, page);
112static int duplex_fifo(
void) {
113 int failed = 0, fd = -1, notify = -1, created = 0;
114 char path[128], bytes[3];
115 struct stat metadata;
116 snprintf(path,
sizeof(path),
"/tmp/pipe-transfer-duplex-%ld", (
long)getpid());
117 mode_t previous_mask = umask(0077);
118 int create_result = mkfifo(path, 0666);
119 int create_errno = errno;
120 umask(previous_mask);
121 errno = create_errno;
122 CHECK(!create_result);
124 CHECK((fd = open(path, O_RDWR | O_NONBLOCK)) >= 0);
125 CHECK(!fstat(fd, &metadata) && S_ISFIFO(metadata.st_mode) && (metadata.st_mode & 07777) == 0600 &&
126 metadata.st_uid == geteuid() && metadata.st_gid == getegid());
127 CHECK(mkfifo(path, 0666) == -1 && errno == EEXIST);
128 CHECK((notify = inotify_init1(IN_NONBLOCK | IN_CLOEXEC)) >= 0);
129 int watch = inotify_add_watch(notify, path, IN_MODIFY);
131 struct iovec vector = {
"abc", 3};
132 CHECK(vmsplice(fd, &vector, 1, SPLICE_F_NONBLOCK) == 3);
134 struct inotify_event event;
137 CHECK(pt_ready(notify, POLLIN, 1000) == 1 &&
138 read(notify, event.bytes,
sizeof(event.bytes)) >= (ssize_t)
sizeof(event.event) &&
139 event.event.wd == watch && (event.event.mask & IN_MODIFY));
140 CHECK(read(fd, bytes,
sizeof(bytes)) ==
sizeof(bytes) && !memcmp(bytes,
"abc",
sizeof(bytes)));
150int pipe_transfer_vmsplice(
void) {
151 return copying() || faults_and_limits() || aligned_gift() || duplex_fifo();