[PATCH] Formalize input/output pipe checking
[splice.git] / vmsplice.c
CommitLineData
7ee0f27f
JA
1/*
2 * Use vmsplice to fill some user memory into a pipe. vmsplice writes
3 * to stdout, so that must be a pipe.
4 */
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
7ee0f27f 8#include <limits.h>
dbcd0883
JA
9#include <string.h>
10#include <getopt.h>
7ee0f27f 11#include <sys/poll.h>
7ee0f27f
JA
12#include <sys/types.h>
13
14#include "splice.h"
15
88a9ff87 16#define ALIGN(buf) (void *) (((unsigned long) (buf) + align_mask) & ~align_mask)
7ee0f27f 17
dbcd0883 18static int do_clear;
88a9ff87 19static int align_mask = 65535;
dbcd0883 20
88a9ff87 21int do_vmsplice(int fd, void *b1, void *b2, int len)
7ee0f27f
JA
22{
23 struct pollfd pfd = { .fd = fd, .events = POLLOUT, };
88a9ff87
JA
24 struct iovec iov[] = {
25 {
26 .iov_base = b1,
27 .iov_len = len / 2,
28 },
29 {
30 .iov_base = b2,
31 .iov_len = len / 2,
32 },
33 };
34 int written, idx = 0;
7ee0f27f
JA
35
36 while (len) {
37 /*
38 * in a real app you'd be more clever with poll of course,
39 * here we are basically just blocking on output room and
40 * not using the free time for anything interesting.
41 */
42 if (poll(&pfd, 1, -1) < 0)
43 return error("poll");
44
88a9ff87 45 written = vmsplice(fd, &iov[idx], 2 - idx, 0);
7ee0f27f
JA
46
47 if (written <= 0)
48 return error("vmsplice");
49
50 len -= written;
88a9ff87
JA
51 if (written >= iov[idx].iov_len) {
52 int extra = written - iov[idx].iov_len;
53
54 idx++;
55 iov[idx].iov_len -= extra;
56 iov[idx].iov_base += extra;
57 } else {
58 iov[idx].iov_len -= written;
59 iov[idx].iov_base += written;
60 }
7ee0f27f
JA
61 }
62
63 return 0;
64}
65
dbcd0883
JA
66static int usage(char *name)
67{
f91353a3 68 fprintf(stderr, "%s: [-c(lear)] [-u(nalign)] | ...\n", name);
dbcd0883
JA
69 return 1;
70}
71
72static int parse_options(int argc, char *argv[])
73{
74 int c, index = 1;
75
88a9ff87 76 while ((c = getopt(argc, argv, "cu")) != -1) {
dbcd0883
JA
77 switch (c) {
78 case 'c':
79 do_clear = 1;
80 index++;
81 break;
88a9ff87
JA
82 case 'u':
83 align_mask = 0;
84 index++;
85 break;
dbcd0883
JA
86 default:
87 return -1;
88 }
89 }
90
91 return index;
92}
93
7ee0f27f
JA
94int main(int argc, char *argv[])
95{
88a9ff87 96 unsigned char *b1, *b2;
7ee0f27f 97
dbcd0883
JA
98 if (parse_options(argc, argv) < 0)
99 return usage(argv[0]);
100
76797253 101 if (check_output_pipe())
f91353a3 102 return usage(argv[0]);
7ee0f27f 103
88a9ff87
JA
104 b1 = ALIGN(malloc(SPLICE_SIZE + align_mask));
105 b2 = ALIGN(malloc(SPLICE_SIZE + align_mask));
106
107 memset(b1, 0xaa, SPLICE_SIZE);
108 memset(b2, 0xbb, SPLICE_SIZE);
7ee0f27f
JA
109
110 do {
88a9ff87
JA
111 int half = SPLICE_SIZE / 2;
112
7ee0f27f
JA
113 /*
114 * vmsplice the first half of the buffer into the pipe
115 */
88a9ff87 116 if (do_vmsplice(STDOUT_FILENO, b1, b2, SPLICE_SIZE))
7ee0f27f
JA
117 break;
118
119 /*
120 * first half is now in pipe, but we don't quite know when
121 * we can reuse it.
122 */
123
124 /*
125 * vmsplice second half
126 */
88a9ff87 127 if (do_vmsplice(STDOUT_FILENO, b1 + half, b2 + half, SPLICE_SIZE))
7ee0f27f
JA
128 break;
129
130 /*
131 * We still don't know when we can reuse the second half of
132 * the buffer, but we do now know that all parts of the first
133 * half have been consumed from the pipe - so we can reuse that.
134 */
dbcd0883
JA
135
136 /*
137 * Test option - clear the first half of the buffer, should
138 * be safe now
139 */
88a9ff87
JA
140 if (do_clear) {
141 memset(b1, 0x00, SPLICE_SIZE);
142 memset(b2, 0x00, SPLICE_SIZE);
143 }
7ee0f27f
JA
144 } while (0);
145
146 return 0;
147}