Commit | Line | Data |
---|---|---|
648a7fef 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> | |
8 | #include <limits.h> | |
9 | #include <string.h> | |
10 | #include <getopt.h> | |
11 | #include <sys/poll.h> | |
12 | #include <sys/types.h> | |
13 | ||
14 | #include "splice.h" | |
15 | ||
257812cf JA |
16 | #define PAGE_SIZE 4096 |
17 | #define PAGE_MASK (PAGE_SIZE - 1) | |
257812cf | 18 | |
9649cd9b | 19 | static int alloc_stack; |
257812cf | 20 | static int cross_page; |
fa26bccb JA |
21 | static int force_align; |
22 | static int full_page; | |
23 | static int gift; | |
9649cd9b | 24 | |
648a7fef JA |
25 | int do_vmsplice(int fd, struct iovec *iov, unsigned long nr_vecs) |
26 | { | |
27 | struct pollfd pfd = { .fd = fd, .events = POLLOUT, }; | |
28 | long written; | |
29 | ||
30 | while (nr_vecs) { | |
31 | /* | |
32 | * in a real app you'd be more clever with poll of course, | |
33 | * here we are basically just blocking on output room and | |
34 | * not using the free time for anything interesting. | |
35 | */ | |
36 | if (poll(&pfd, 1, -1) < 0) | |
37 | return error("poll"); | |
38 | ||
13b72067 | 39 | written = svmsplice(fd, iov, nr_vecs, gift ? SPLICE_F_GIFT : 0); |
648a7fef JA |
40 | |
41 | if (written <= 0) | |
42 | return error("vmsplice"); | |
43 | ||
44 | while (written) { | |
45 | int this_len = iov->iov_len; | |
46 | ||
47 | if (this_len > written) | |
48 | this_len = written; | |
49 | ||
50 | iov->iov_len -= this_len; | |
51 | if (!iov->iov_len) { | |
52 | nr_vecs--; | |
53 | iov++; | |
54 | } | |
55 | ||
56 | written -= this_len; | |
57 | } | |
58 | } | |
59 | ||
60 | return 0; | |
61 | } | |
62 | ||
63 | static int usage(char *name) | |
64 | { | |
fa26bccb | 65 | fprintf(stderr, "%s [-s(tack)] [-c(ross page)] [-a(lign)] [-f(ull page)] [-g(ift)] | ...\n", name); |
648a7fef JA |
66 | return 1; |
67 | } | |
68 | ||
9649cd9b JA |
69 | static int parse_options(int argc, char *argv[]) |
70 | { | |
71 | int c, index = 1; | |
72 | ||
fa26bccb | 73 | while ((c = getopt(argc, argv, "scafg")) != -1) { |
9649cd9b JA |
74 | switch (c) { |
75 | case 's': | |
76 | alloc_stack = 1; | |
77 | index++; | |
78 | break; | |
257812cf JA |
79 | case 'c': |
80 | cross_page = 1; | |
81 | index++; | |
82 | break; | |
fa26bccb JA |
83 | case 'a': |
84 | force_align = 1; | |
85 | index++; | |
86 | break; | |
87 | case 'f': | |
88 | full_page = 1; | |
89 | index++; | |
90 | break; | |
91 | case 'g': | |
92 | gift = 1; | |
93 | index++; | |
94 | break; | |
9649cd9b JA |
95 | default: |
96 | return -1; | |
97 | } | |
98 | } | |
99 | ||
fa26bccb JA |
100 | if (cross_page && force_align) { |
101 | fprintf(stderr, "Can't get both aligning and cross page spanning\n"); | |
102 | return -1; | |
103 | } | |
257812cf | 104 | |
9649cd9b JA |
105 | return index; |
106 | } | |
107 | ||
fa26bccb | 108 | #define ASIZE (3 * PAGE_SIZE) |
238a8608 JA |
109 | #define S1 "header header header header header header header header " |
110 | #define S2 "body body body body body body body body body body body " | |
e346936e JA |
111 | #define S3 "footer footer footer footer footer footer footer footer" |
112 | ||
fa26bccb JA |
113 | static void check_address(void *addr, void *start, void *end, int len,char *msg) |
114 | { | |
115 | if (addr < start || (addr + len - 1) > end) | |
116 | fprintf(stderr, "%s: bad: %p < %p < %p false\n", msg, start, addr, end); | |
117 | } | |
118 | ||
648a7fef JA |
119 | int main(int argc, char *argv[]) |
120 | { | |
648a7fef | 121 | struct iovec vecs[3]; |
fa26bccb JA |
122 | char stack1[ASIZE], stack2[ASIZE], stack3[ASIZE]; |
123 | char *h_s, *h_e, *b_s, *b_e, *f_s, *f_e; | |
9649cd9b | 124 | char *h, *b, *f; |
fa26bccb JA |
125 | |
126 | if (check_output_pipe()) | |
127 | return usage(argv[0]); | |
9649cd9b JA |
128 | |
129 | if (parse_options(argc, argv) < 0) | |
130 | return usage(argv[0]); | |
131 | ||
132 | if (alloc_stack) { | |
fa26bccb JA |
133 | h = stack1; |
134 | b = stack2; | |
135 | f = stack3; | |
9649cd9b | 136 | } else { |
fa26bccb JA |
137 | h = malloc(ASIZE); |
138 | b = malloc(ASIZE); | |
139 | f = malloc(ASIZE); | |
140 | } | |
141 | ||
142 | memset(h, 0, ASIZE); | |
143 | memset(b, 0, ASIZE); | |
144 | memset(f, 0, ASIZE); | |
145 | ||
146 | h_s = h; | |
147 | h_e = h_s + 2 * PAGE_SIZE - 1; | |
148 | b_s = b; | |
149 | b_e = b_s + 2 * PAGE_SIZE - 1; | |
150 | f_s = f; | |
151 | f_e = f_s + 2 * PAGE_SIZE - 1; | |
152 | ||
153 | if (force_align || cross_page) { | |
154 | /* align forward to start of 2nd page */ | |
155 | unsigned long off; | |
156 | ||
157 | off = PAGE_SIZE - ((unsigned long) h & PAGE_MASK); | |
158 | h += off; | |
159 | off = PAGE_SIZE - ((unsigned long) b & PAGE_MASK); | |
160 | b += off; | |
161 | off = PAGE_SIZE - ((unsigned long) f & PAGE_MASK); | |
162 | f += off; | |
257812cf | 163 | if (cross_page) { |
fa26bccb JA |
164 | /* this puts half the string in both pages */ |
165 | h -= strlen(S1) / 2; | |
166 | b -= strlen(S2) / 2; | |
167 | f -= strlen(S3) / 2; | |
257812cf | 168 | } |
9649cd9b | 169 | } |
648a7fef | 170 | |
fa26bccb JA |
171 | strcpy(h, S1); |
172 | strcpy(b, S2); | |
173 | strcpy(f, S3); | |
174 | ||
648a7fef | 175 | vecs[0].iov_base = h; |
648a7fef | 176 | vecs[1].iov_base = b; |
648a7fef | 177 | vecs[2].iov_base = f; |
fa26bccb JA |
178 | if (!full_page) { |
179 | vecs[0].iov_len = strlen(vecs[0].iov_base); | |
180 | vecs[1].iov_len = strlen(vecs[1].iov_base); | |
181 | vecs[2].iov_len = strlen(vecs[2].iov_base); | |
182 | } else { | |
183 | vecs[0].iov_len = PAGE_SIZE; | |
184 | vecs[1].iov_len = PAGE_SIZE; | |
185 | vecs[2].iov_len = PAGE_SIZE; | |
186 | } | |
187 | ||
188 | check_address(h, h_s, h_e, vecs[0].iov_len, "header"); | |
189 | check_address(b, b_s, b_e, vecs[1].iov_len, "body"); | |
190 | check_address(f, f_s, f_e, vecs[2].iov_len, "footer"); | |
648a7fef JA |
191 | |
192 | return do_vmsplice(STDOUT_FILENO, vecs, 3); | |
193 | } |