LCOV - code coverage report
Current view: top level - control - tap-ctl-ipc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 78 115 67.8 %
Date: 2025-02-07 10:27:58 Functions: 8 10 80.0 %
Branches: 51 114 44.7 %

           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 "blktap.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                 :            : }

Generated by: LCOV version 1.13