vmsplice-touser: -z requires -m
[splice.git] / vmsplice-touser.c
CommitLineData
d07a80dc
JA
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>
0a6ff83b 10#include <fcntl.h>
d07a80dc
JA
11#include <sys/poll.h>
12#include <sys/types.h>
13
14#include "splice.h"
15
16static int do_dump;
ef0e4210
JA
17static int do_ascii;
18static int do_zeromap;
d07a80dc
JA
19static int splice_flags;
20
ef0e4210
JA
21static 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
31static int do_vmsplice(int fd, unsigned char **buf, int len)
d07a80dc
JA
32{
33 struct pollfd pfd = { .fd = fd, .events = POLLIN, };
34 struct iovec iov;
35 int written;
36 int ret;
37
ef0e4210 38 iov.iov_base = *buf;
d07a80dc
JA
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
13b72067 51 written = svmsplice(fd, &iov, 1, splice_flags);
1e404f5c 52 *buf = iov.iov_base;
d07a80dc
JA
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
70static int usage(char *name)
71{
ef0e4210 72 fprintf(stderr, "| %s [-d(ump)] [-a(ascii)] [-m(ap)] [-z(eromap)]\n", name);
d07a80dc
JA
73 return 1;
74}
75
76static int parse_options(int argc, char *argv[])
77{
78 int c, index = 1;
79
ef0e4210 80 while ((c = getopt(argc, argv, "admz")) != -1) {
d07a80dc 81 switch (c) {
ef0e4210
JA
82 case 'a':
83 do_ascii = 1;
84 index++;
85 break;
d07a80dc
JA
86 case 'd':
87 do_dump = 1;
88 index++;
89 break;
ef0e4210
JA
90 case 'm':
91 splice_flags |= SPLICE_F_MOVE;
92 index++;
93 break;
94 case 'z':
95 do_zeromap = 1;
96 index++;
97 break;
d07a80dc
JA
98 default:
99 return -1;
100 }
101 }
102
103 return index;
104}
105
106static void hexdump(unsigned char *buf, int len)
107{
108 int i;
109
110 for (i = 0; i < len; i++)
111 printf("%02x", buf[i]);
ef0e4210
JA
112}
113
114static void asciidump(unsigned char *buf, int len)
115{
116 int i;
117
118 for (i = 0; i < len; i++)
119 printf("%c", buf[i]);
d07a80dc
JA
120}
121
122int 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
1e404f5c
JA
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
ef0e4210
JA
138 if (!do_zeromap) {
139 buf = malloc(4096);
140 memset(buf, 0, 4096);
141 } else
142 buf = NULL;
d07a80dc 143
ef0e4210 144 ret = do_vmsplice(STDIN_FILENO, &buf, 4096);
d07a80dc
JA
145 if (ret < 0)
146 return 1;
147
d07a80dc
JA
148 if (do_dump)
149 hexdump(buf, ret);
ef0e4210
JA
150 if (do_ascii)
151 asciidump(buf, ret);
d07a80dc 152
ef0e4210
JA
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;
d07a80dc 160}