[PATCH] vmsplice2: page spanning needs 3 pages
[splice.git] / vmsplice2.c
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
16 #define PAGE_SIZE       4096
17 #define PAGE_MASK       (PAGE_SIZE - 1)
18 #define ALIGN(buf)      (void *) (((unsigned long) (buf) + PAGE_MASK) & ~PAGE_MASK)
19
20 static int alloc_stack;
21 static int cross_page;
22
23 int do_vmsplice(int fd, struct iovec *iov, unsigned long nr_vecs)
24 {
25         struct pollfd pfd = { .fd = fd, .events = POLLOUT, };
26         long written;
27
28         while (nr_vecs) {
29                 /*
30                  * in a real app you'd be more clever with poll of course,
31                  * here we are basically just blocking on output room and
32                  * not using the free time for anything interesting.
33                  */
34                 if (poll(&pfd, 1, -1) < 0)
35                         return error("poll");
36
37                 written = vmsplice(fd, iov, nr_vecs, 0);
38
39                 if (written <= 0)
40                         return error("vmsplice");
41
42                 while (written) {
43                         int this_len = iov->iov_len;
44
45                         if (this_len > written)
46                                 this_len = written;
47
48                         iov->iov_len -= this_len;
49                         if (!iov->iov_len) {
50                                 nr_vecs--;
51                                 iov++;
52                         }
53
54                         written -= this_len;
55                 }
56         }
57
58         return 0;
59 }
60
61 static int usage(char *name)
62 {
63         fprintf(stderr, "%s [-s(tack)] [-c(ross page)]| ...\n", name);
64         return 1;
65 }
66
67 static int parse_options(int argc, char *argv[])
68 {
69         int c, index = 1;
70
71         while ((c = getopt(argc, argv, "sc")) != -1) {
72                 switch (c) {
73                 case 's':
74                         alloc_stack = 1;
75                         index++;
76                         break;
77                 case 'c':
78                         cross_page = 1;
79                         index++;
80                         break;
81                 default:
82                         return -1;
83                 }
84         }
85
86         if (alloc_stack && cross_page)
87                 fprintf(stderr, "Stack alloc and cross page are mutually exclusive\n");
88
89         return index;
90 }
91
92 #define S1      "header header header header header header header header "
93 #define S2      "body body body body body body body body body body body "
94 #define S3      "footer footer footer footer footer footer footer footer"
95
96 int main(int argc, char *argv[])
97 {
98         struct iovec vecs[3];
99         char *h, *b, *f;
100
101         if (parse_options(argc, argv) < 0)
102                 return usage(argv[0]);
103
104         if (alloc_stack) {
105                 h = S1;
106                 b = S2;
107                 f = S3;
108         } else {
109                 if (cross_page) {
110                         void *ptr;
111
112                         ptr = ALIGN(malloc(3 * PAGE_SIZE));
113                         h = ptr + PAGE_SIZE - (strlen(S1) / 2);
114                         strcpy(h, S1);
115
116                         ptr = ALIGN(malloc(3 * PAGE_SIZE));
117                         b = ptr + PAGE_SIZE - (strlen(S2) / 2);
118                         strcpy(b, S2);
119
120                         ptr = ALIGN(malloc(3 * PAGE_SIZE));
121                         f = ptr + PAGE_SIZE - (strlen(S3) / 2);
122                         strcpy(f, S3);
123                 } else {
124                         h = strdup(S1);
125                         b = strdup(S2);
126                         f = strdup(S3);
127                 }
128         }
129
130         vecs[0].iov_base = h;
131         vecs[1].iov_base = b;
132         vecs[2].iov_base = f;
133         vecs[0].iov_len = strlen(vecs[0].iov_base);
134         vecs[1].iov_len = strlen(vecs[1].iov_base);
135         vecs[2].iov_len = strlen(vecs[2].iov_base);
136                 
137         if (check_output_pipe())
138                 return usage(argv[0]);
139
140         return do_vmsplice(STDOUT_FILENO, vecs, 3);
141 }