vmsplice-touser: -z requires -m
[splice.git] / vmsplice-touser.c
1 /*
2  * Use vmsplice to splice data from a pipe to user space memory.
3  */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <unistd.h>
7 #include <limits.h>
8 #include <string.h>
9 #include <getopt.h>
10 #include <fcntl.h>
11 #include <sys/poll.h>
12 #include <sys/types.h>
13
14 #include "splice.h"
15
16 static int do_dump;
17 static int do_ascii;
18 static int do_zeromap;
19 static int splice_flags;
20
21 static int do_vmsplice_unmap(int fd, unsigned char *buf, int len)
22 {
23         struct iovec iov = {
24                 .iov_base = buf,
25                 .iov_len = len,
26         };
27
28         return svmsplice(fd, &iov, 1, SPLICE_F_UNMAP);
29 }
30
31 static int do_vmsplice(int fd, unsigned char **buf, int len)
32 {
33         struct pollfd pfd = { .fd = fd, .events = POLLIN, };
34         struct iovec iov;
35         int written;
36         int ret;
37
38         iov.iov_base = *buf;
39         iov.iov_len = len;
40         ret = 0;
41
42         while (len) {
43                 /*
44                  * in a real app you'd be more clever with poll of course,
45                  * here we are basically just blocking on output room and
46                  * not using the free time for anything interesting.
47                  */
48                 if (poll(&pfd, 1, -1) < 0)
49                         return error("poll");
50
51                 written = svmsplice(fd, &iov, 1, splice_flags);
52                 *buf = iov.iov_base;
53
54                 if (written < 0)
55                         return error("vmsplice");
56                 else if (!written)
57                         break;
58
59                 len -= written;
60                 ret += written;
61                 if (len) {
62                         iov.iov_len -= written;
63                         iov.iov_base += written;
64                 }
65         }
66
67         return ret;
68 }
69
70 static int usage(char *name)
71 {
72         fprintf(stderr, "| %s [-d(ump)] [-a(ascii)] [-m(ap)] [-z(eromap)]\n", name);
73         return 1;
74 }
75
76 static int parse_options(int argc, char *argv[])
77 {
78         int c, index = 1;
79
80         while ((c = getopt(argc, argv, "admz")) != -1) {
81                 switch (c) {
82                 case 'a':
83                         do_ascii = 1;
84                         index++;
85                         break;
86                 case 'd':
87                         do_dump = 1;
88                         index++;
89                         break;
90                 case 'm':
91                         splice_flags |= SPLICE_F_MOVE;
92                         index++;
93                         break;
94                 case 'z':
95                         do_zeromap = 1;
96                         index++;
97                         break;
98                 default:
99                         return -1;
100                 }
101         }
102
103         return index;
104 }
105
106 static void hexdump(unsigned char *buf, int len)
107 {
108         int i;
109
110         for (i = 0; i < len; i++)
111                 printf("%02x", buf[i]);
112 }
113
114 static void asciidump(unsigned char *buf, int len)
115 {
116         int i;
117
118         for (i = 0; i < len; i++)
119                 printf("%c", buf[i]);
120 }
121
122 int main(int argc, char *argv[])
123 {
124         unsigned char *buf;
125         int ret;
126
127         if (parse_options(argc, argv) < 0)
128                 return usage(argv[0]);
129
130         if (check_input_pipe())
131                 return usage(argv[0]);
132
133         if (do_zeromap && !(splice_flags & SPLICE_F_MOVE)) {
134                 fprintf(stderr, "zero map only valid for -m(ove)\n");
135                 return usage(argv[0]);
136         }
137
138         if (!do_zeromap) {
139                 buf = malloc(4096);
140                 memset(buf, 0, 4096);
141         } else
142                 buf = NULL;
143
144         ret = do_vmsplice(STDIN_FILENO, &buf, 4096);
145         if (ret < 0)
146                 return 1;
147
148         if (do_dump)
149                 hexdump(buf, ret);
150         if (do_ascii)
151                 asciidump(buf, ret);
152
153         if (splice_flags & SPLICE_F_MOVE) {
154                 ret = do_vmsplice_unmap(STDIN_FILENO, buf, 4096);
155                 if (ret < 0)
156                         perror("vmsplice");
157         }
158
159         return ret;
160 }