Fix various compile warnings
[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
19 static int alloc_stack;
20 static int cross_page;
21 static int force_align;
22 static int full_page;
23 static int gift;
24
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
39                 written = svmsplice(fd, iov, nr_vecs, gift ? SPLICE_F_GIFT : 0);
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 {
65         fprintf(stderr, "%s [-s(tack)] [-c(ross page)] [-a(lign)] [-f(ull page)] [-g(ift)] | ...\n", name);
66         return 1;
67 }
68
69 static int parse_options(int argc, char *argv[])
70 {
71         int c, index = 1;
72
73         while ((c = getopt(argc, argv, "scafg")) != -1) {
74                 switch (c) {
75                 case 's':
76                         alloc_stack = 1;
77                         index++;
78                         break;
79                 case 'c':
80                         cross_page = 1;
81                         index++;
82                         break;
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;
95                 default:
96                         return -1;
97                 }
98         }
99
100         if (cross_page && force_align) {
101                 fprintf(stderr, "Can't get both aligning and cross page spanning\n");
102                 return -1;
103         }
104
105         return index;
106 }
107
108 #define ASIZE   (3 * PAGE_SIZE)
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 "
111 #define S3      "footer footer footer footer footer footer footer footer"
112
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
119 int main(int argc, char *argv[])
120 {
121         struct iovec vecs[3];
122         char stack1[ASIZE], stack2[ASIZE], stack3[ASIZE];
123         char *h_s, *h_e, *b_s, *b_e, *f_s, *f_e;
124         char *h, *b, *f;
125
126         if (check_output_pipe())
127                 return usage(argv[0]);
128
129         if (parse_options(argc, argv) < 0)
130                 return usage(argv[0]);
131
132         if (alloc_stack) {
133                 h = stack1;
134                 b = stack2;
135                 f = stack3;
136         } else {
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;
163                 if (cross_page) {
164                         /* this puts half the string in both pages */
165                         h -= strlen(S1) / 2;
166                         b -= strlen(S2) / 2;
167                         f -= strlen(S3) / 2;
168                 }
169         }
170
171         strcpy(h, S1);
172         strcpy(b, S2);
173         strcpy(f, S3);
174
175         vecs[0].iov_base = h;
176         vecs[1].iov_base = b;
177         vecs[2].iov_base = f;
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");
191
192         return do_vmsplice(STDOUT_FILENO, vecs, 3);
193 }