Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <stdio.h>
36 : : #include <errno.h>
37 : : #include <stdlib.h>
38 : : #include <string.h>
39 : : #include <unistd.h>
40 : : #include <fcntl.h>
41 : : #include <sys/un.h>
42 : : #include <sys/stat.h>
43 : : #include <sys/types.h>
44 : : #include <sys/socket.h>
45 : :
46 : : #include "tap-ctl.h"
47 : : #include "blktap2.h"
48 : : #include "compiler.h"
49 : : #include "util.h"
50 : :
51 : : int tap_ctl_debug = 0;
52 : :
53 : : #define eintr_retry(res, op) \
54 : : do { \
55 : : res = op; \
56 : : } while (res == -1 && errno == EINTR);
57 : :
58 : : int
59 : 14 : tap_ctl_read_raw(int fd, void *buf, size_t size, struct timeval *timeout)
60 : : {
61 : : fd_set readfds;
62 : 14 : size_t offset = 0;
63 : : int ret;
64 : 14 : int err = 0;
65 : :
66 : 14 : FD_ZERO(&readfds);
67 [ + + ]: 26 : while (offset < size) {
68 [ - + ][ # # ]: 14 : FD_SET(fd, &readfds);
69 : :
70 [ - + ][ # # ]: 14 : eintr_retry(ret, select(fd + 1, &readfds, NULL, NULL, timeout))
71 [ - + ]: 14 : if (ret == -1) {
72 : 0 : err = errno;
73 : 0 : break;
74 [ - + ][ # # ]: 14 : } else if (FD_ISSET(fd, &readfds)) {
[ + + ]
75 [ + + ][ - + ]: 13 : eintr_retry(ret, read(fd, buf + offset, size - offset))
76 [ + + ]: 13 : if (ret <= 0) {
77 : 1 : err = errno;
78 : 1 : break;
79 : : }
80 : 12 : offset += ret;
81 : : } else {
82 : : /* 0 return - timed out */
83 : : err = ETIMEDOUT;
84 : : break;
85 : : }
86 : :
87 : : }
88 : :
89 [ + + ]: 14 : if (offset != size) {
90 : : EPRINTF("failure reading data %zd/%zd\n", offset, size);
91 [ + - ]: 2 : return err ? - err : -EIO;
92 : : }
93 : :
94 : : return 0;
95 : : }
96 : :
97 : : int
98 : 14 : tap_ctl_read_message(int fd, tapdisk_message_t *message,
99 : : struct timeval *timeout)
100 : : {
101 : 14 : size_t size = sizeof(tapdisk_message_t);
102 : : int err;
103 : :
104 : 14 : err = tap_ctl_read_raw(fd, message, size, timeout);
105 [ + + ]: 14 : if (err)
106 : : return err;
107 : :
108 [ - + ][ # # ]: 12 : DBG("received '%s' message (uuid = %u)\n",
109 : : tapdisk_message_name(message->type), message->cookie);
110 : :
111 : : return 0;
112 : : }
113 : :
114 : : int
115 : 13 : tap_ctl_write_message(int fd, tapdisk_message_t *message, struct timeval *timeout)
116 : : {
117 : : fd_set writefds;
118 : : int ret, len, offset;
119 : :
120 : 13 : offset = 0;
121 : 13 : len = sizeof(tapdisk_message_t);
122 : :
123 [ - + ][ # # ]: 13 : DBG("sending '%s' message (uuid = %u)\n",
124 : : tapdisk_message_name(message->type), message->cookie);
125 : :
126 [ + + ]: 24 : while (offset < len) {
127 : 13 : FD_ZERO(&writefds);
128 [ - + ][ # # ]: 13 : FD_SET(fd, &writefds);
129 : :
130 : : /* we don't bother reinitializing tv. at worst, it will wait a
131 : : * bit more time than expected. */
132 : :
133 [ - + ][ # # ]: 13 : eintr_retry(ret, select(fd + 1, NULL, &writefds, NULL, timeout))
134 [ + - ]: 13 : if (ret == -1)
135 : : break;
136 [ - + ][ # # ]: 13 : else if (FD_ISSET(fd, &writefds)) {
[ + + ]
137 [ + + ][ - + ]: 12 : eintr_retry(ret, write(fd, (uint8_t*)message + offset, len - offset))
138 [ + + ]: 12 : if (ret <= 0)
139 : : break;
140 : 11 : offset += ret;
141 : : } else
142 : : break;
143 : : }
144 : :
145 [ + + ]: 13 : if (offset != len) {
146 : : EPRINTF("failure writing message\n");
147 : 13 : return -EIO;
148 : : }
149 : :
150 : : return 0;
151 : : }
152 : :
153 : : int
154 : 10 : tap_ctl_send_and_receive(int sfd, tapdisk_message_t *message,
155 : : struct timeval *timeout)
156 : : {
157 : : int err;
158 : :
159 : 10 : err = tap_ctl_write_message(sfd, message, timeout);
160 [ + + ]: 10 : if (err) {
161 [ + - ]: 2 : EPRINTF("failed to send '%s' message\n",
162 : : tapdisk_message_name(message->type));
163 : 2 : return err;
164 : : }
165 : :
166 : 8 : err = tap_ctl_read_message(sfd, message, timeout);
167 [ + + ]: 8 : if (err) {
168 [ + - ]: 2 : EPRINTF("failed to receive '%s' message\n",
169 : : tapdisk_message_name(message->type));
170 : 2 : return err;
171 : : }
172 : :
173 : : return 0;
174 : : }
175 : :
176 : : int
177 : 0 : tap_ctl_send_and_receive_ex(int sfd, tapdisk_message_t *message,
178 : : const char *logpath, uint8_t key_size,
179 : : const uint8_t *encryption_key,
180 : : struct timeval *timeout)
181 : : {
182 : : int err, ret;
183 : :
184 : 0 : err = tap_ctl_write_message(sfd, message, timeout);
185 [ # # ]: 0 : if (err) {
186 [ # # ]: 0 : EPRINTF("failed to send '%s' message\n",
187 : : tapdisk_message_name(message->type));
188 : 0 : return err;
189 : : }
190 : :
191 [ # # ]: 0 : if (message->u.params.flags & TAPDISK_MESSAGE_FLAG_ADD_LOG) {
192 : : char buf[TAPDISK_MESSAGE_MAX_PATH_LENGTH];
193 : :
194 : : snprintf(buf, TAPDISK_MESSAGE_MAX_PATH_LENGTH - 1, "%s", logpath);
195 : :
196 : 0 : ret = write(sfd, &buf, sizeof(buf));
197 : :
198 [ # # ]: 0 : if (ret == -1) {
199 [ # # ]: 0 : EPRINTF("Failed to send logpath with '%s' message\n",
200 : : tapdisk_message_name(message->type));
201 : : }
202 : : }
203 : :
204 [ # # ]: 0 : if (message->u.params.flags & TAPDISK_MESSAGE_FLAG_OPEN_ENCRYPTED) {
205 : 0 : DPRINTF("Sending encryption key of %d bits\n", (int)key_size * 8);
206 : 0 : ret = write(sfd, &key_size, sizeof(key_size));
207 [ # # ]: 0 : if (ret != sizeof(key_size)) {
208 [ # # ]: 0 : EPRINTF("Failed to send encryption key size with '%s' message\n",
209 : : tapdisk_message_name(message->type));
210 : 0 : return EIO;
211 : : }
212 : 0 : ret = write(sfd, encryption_key, key_size);
213 [ # # ]: 0 : if (ret != key_size) {
214 [ # # ]: 0 : EPRINTF("Failed to send encryption key with '%s' message\n",
215 : : tapdisk_message_name(message->type));
216 : 0 : return EIO;
217 : : }
218 : : }
219 : :
220 : 0 : err = tap_ctl_read_message(sfd, message, timeout);
221 [ # # ]: 0 : if (err) {
222 [ # # ]: 0 : EPRINTF("failed to receive '%s' message\n",
223 : : tapdisk_message_name(message->type));
224 : 0 : return err;
225 : : }
226 : :
227 : : return 0;
228 : : }
229 : :
230 : : char *
231 : 14 : tap_ctl_socket_name(int id)
232 : : {
233 : : char *name;
234 : :
235 [ + - ]: 14 : if (asprintf(&name, "%s/%s%d",
236 : : BLKTAP2_CONTROL_DIR, BLKTAP2_CONTROL_SOCKET, id) == -1)
237 : : return NULL;
238 : :
239 : 14 : return name;
240 : : }
241 : :
242 : : int
243 : 14 : tap_ctl_connect(const char *name, int *sfd)
244 : : {
245 : : int fd, err;
246 : : struct sockaddr_un saddr;
247 : :
248 : 14 : *sfd = -1;
249 : :
250 : 14 : fd = socket(AF_UNIX, SOCK_STREAM, 0);
251 [ - + ]: 14 : if (fd == -1) {
252 : 0 : EPRINTF("couldn't create socket for %s: %s\n", name, strerror(errno));
253 : 0 : return -errno;
254 : : }
255 : :
256 : : memset(&saddr, 0, sizeof(saddr));
257 : 14 : saddr.sun_family = AF_UNIX;
258 : :
259 [ - + ]: 14 : if (unlikely(strlen(name) >= sizeof(saddr.sun_path))) {
260 : : EPRINTF("socket name too long: %s\n", name);
261 : 0 : close(fd);
262 : : return -ENAMETOOLONG;
263 : : }
264 : :
265 : 14 : safe_strncpy(saddr.sun_path, name, sizeof(saddr.sun_path));
266 : :
267 : 14 : err = connect(fd, (const struct sockaddr *)&saddr, sizeof(saddr));
268 [ + + ]: 14 : if (err) {
269 : 1 : err = errno;
270 [ + - ]: 1 : if (likely(err == ENOENT))
271 : 1 : DPRINTF("couldn't connect to %s: %s\n", name, strerror(err));
272 : : else
273 : 0 : EPRINTF("couldn't connect to %s: %s\n", name, strerror(err));
274 : 1 : close(fd);
275 : 1 : return -err;
276 : : }
277 : :
278 : 13 : *sfd = fd;
279 : 13 : return 0;
280 : : }
281 : :
282 : : int
283 : 14 : tap_ctl_connect_id(int id, int *sfd)
284 : : {
285 : : int err;
286 : : char *name;
287 : :
288 : 14 : *sfd = -1;
289 : :
290 [ - + ]: 14 : if (id < 0) {
291 : : EPRINTF("invalid id %d\n", id);
292 : 0 : return -EINVAL;
293 : : }
294 : :
295 : 14 : name = tap_ctl_socket_name(id);
296 [ - + ]: 14 : if (!name) {
297 : : EPRINTF("couldn't name socket for %d\n", id);
298 : 0 : return -ENOMEM;
299 : : }
300 : :
301 : 14 : err = tap_ctl_connect(name, sfd);
302 : :
303 : 14 : free(name);
304 : :
305 : 14 : return err;
306 : : }
307 : :
308 : : int
309 : 11 : tap_ctl_connect_send_and_receive(int id, tapdisk_message_t *message,
310 : : struct timeval *timeout)
311 : : {
312 : : int err, sfd;
313 : :
314 : 11 : err = tap_ctl_connect_id(id, &sfd);
315 [ + + ]: 11 : if (err)
316 : 11 : return err;
317 : :
318 : 10 : err = tap_ctl_send_and_receive(sfd, message, timeout);
319 : :
320 : 10 : close(sfd);
321 : : return err;
322 : : }
323 : :
324 : : int
325 : 0 : tap_ctl_connect_send_receive_ex(int id, tapdisk_message_t *message,
326 : : const char *logpath, uint8_t key_size,
327 : : const uint8_t *encryption_key,
328 : : struct timeval *timeout)
329 : : {
330 : : int err, sfd;
331 : :
332 : 0 : err = tap_ctl_connect_id(id, &sfd);
333 [ # # ]: 0 : if (err)
334 : 0 : return err;
335 : :
336 : 0 : err = tap_ctl_send_and_receive_ex(sfd, message, logpath, key_size, encryption_key, timeout);
337 : :
338 : 0 : close(sfd);
339 : : return err;
340 : : }
|