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