LCOV - code coverage report
Current view: top level - libpkg - fetch_ssh.c (source / functions) Hit Total Coverage
Test: plop Lines: 0 287 0.0 %
Date: 2024-12-28 18:40:32 Functions: 0 10 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 78 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2020 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  * Copyright (c) 2023 Serenity Cyber Security, LLC <license@futurecrew.ru>
       4                 :            :  *                    Author: Gleb Popov <arrowd@FreeBSD.org>
       5                 :            :  *
       6                 :            :  * Redistribution and use in source and binary forms, with or without
       7                 :            :  * modification, are permitted provided that the following conditions
       8                 :            :  * are met:
       9                 :            :  * 1. Redistributions of source code must retain the above copyright
      10                 :            :  *    notice, this list of conditions and the following disclaimer
      11                 :            :  *    in this position and unchanged.
      12                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      13                 :            :  *    notice, this list of conditions and the following disclaimer in the
      14                 :            :  *    documentation and/or other materials provided with the distribution.
      15                 :            :  *
      16                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      17                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      18                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      19                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      20                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      21                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      22                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      23                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      24                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      25                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      26                 :            :  */
      27                 :            : 
      28                 :            : #include <sys/param.h>
      29                 :            : #include <sys/wait.h>
      30                 :            : #include <sys/socket.h>
      31                 :            : #include <sys/time.h>
      32                 :            : #include <sys/types.h>
      33                 :            : 
      34                 :            : #include <ctype.h>
      35                 :            : #include <fcntl.h>
      36                 :            : #include <errno.h>
      37                 :            : #include <stdio.h>
      38                 :            : #include <string.h>
      39                 :            : #include <paths.h>
      40                 :            : #include <poll.h>
      41                 :            : #include <netdb.h>
      42                 :            : #include <time.h>
      43                 :            : 
      44                 :            : #include <bsd_compat.h>
      45                 :            : 
      46                 :            : #include "pkg.h"
      47                 :            : #include "private/event.h"
      48                 :            : #include "private/pkg.h"
      49                 :            : #include "private/fetch.h"
      50                 :            : #include "private/utils.h"
      51                 :            : #include "yuarel.h"
      52                 :            : 
      53                 :            : #ifndef timespeccmp
      54                 :            : #define timespeccmp(tsp, usp, cmp)                                      \
      55                 :            :         (((tsp)->tv_sec == (usp)->tv_sec) ?                               \
      56                 :            :             ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                 \
      57                 :            :             ((tsp)->tv_sec cmp (usp)->tv_sec))
      58                 :            : #endif
      59                 :            : #ifndef timespecsub
      60                 :            : #define timespecsub(tsp, usp, vsp)                                      \
      61                 :            :         do {                                                            \
      62                 :            :                 (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec;         \
      63                 :            :                 (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec;      \
      64                 :            :                 if ((vsp)->tv_nsec < 0) {                         \
      65                 :            :                         (vsp)->tv_sec--;                             \
      66                 :            :                         (vsp)->tv_nsec += 1000000000L;                       \
      67                 :            :                 }                                                       \
      68                 :            :         } while (0)
      69                 :            : #endif
      70                 :            : 
      71                 :            : static int ssh_read(void *data, char *buf, int len);
      72                 :            : static int ssh_write(void *data, const char *buf, int l);
      73                 :            : static int ssh_close(void *data);
      74                 :            : static int tcp_close(void *data);
      75                 :            : 
      76                 :            : static int
      77                 :          0 : tcp_connect(struct pkg_repo *repo, struct yuarel *u)
      78                 :            : {
      79                 :          0 :         char *line = NULL;
      80                 :          0 :         size_t linecap = 0;
      81                 :          0 :         struct addrinfo *ai = NULL, *curai, hints;
      82                 :            :         char srv[NI_MAXSERV];
      83                 :          0 :         int sd = -1;
      84                 :            :         int retcode;
      85                 :            : 
      86                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "TCP> tcp_connect");
      87                 :          0 :         memset(&hints, 0, sizeof(hints));
      88                 :          0 :         hints.ai_family = PF_UNSPEC;
      89         [ #  # ]:          0 :         if (repo->ip == IPV4)
      90                 :          0 :                 hints.ai_family = PF_INET;
      91                 :          0 :         else if (repo->ip == IPV6)
      92                 :          0 :                 hints.ai_family = PF_INET6;
      93                 :          0 :         hints.ai_socktype = SOCK_STREAM;
      94                 :          0 :         snprintf(srv, sizeof(srv), "%d", u->port);
      95                 :          0 :         retcode = getaddrinfo(u->host, srv, &hints, &ai);
      96         [ #  # ]:          0 :         if (retcode != 0) {
      97                 :          0 :                 pkg_emit_pkg_errno(EPKG_NONETWORK, "tcp_connect", gai_strerror(retcode));
      98                 :          0 :                 pkg_emit_error("Unable to lookup for '%s'", u->host);
      99                 :          0 :                 return (EPKG_FATAL);
     100                 :            :         }
     101                 :          0 :         for (curai = ai; curai != NULL; curai = curai->ai_next) {
     102   [ #  #  #  #  :          0 :                 if ((sd = socket(curai->ai_family, curai->ai_socktype,
                   #  # ]
     103                 :          0 :                     curai->ai_protocol)) == -1)
     104                 :          0 :                         continue;
     105         [ #  # ]:          0 :                 if (connect(sd, curai->ai_addr, curai->ai_addrlen) == -1) {
     106                 :          0 :                         close(sd);
     107                 :          0 :                         sd = -1;
     108                 :          0 :                         continue;
     109                 :            :                 }
     110                 :          0 :                 break;
     111                 :            :         }
     112                 :          0 :         freeaddrinfo(ai);
     113         [ #  # ]:          0 :         if (sd == -1) {
     114                 :          0 :                 pkg_emit_pkg_errno(EPKG_NONETWORK, "tcp_connect", NULL);
     115                 :          0 :                 pkg_emit_error("Could not connect to tcp://%s:%d", u->host,
     116                 :          0 :                     u->port);
     117                 :          0 :                 return (EPKG_FATAL);
     118                 :            :         }
     119         [ #  # ]:          0 :         if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &(int){ 1 }, sizeof(int)) != 0) {
     120                 :          0 :                 pkg_emit_errno("Could not connect", "setsockopt");
     121                 :          0 :                 close(sd);
     122                 :          0 :                 return (EPKG_FATAL);
     123                 :            :         }
     124                 :          0 :         repo->sshio.in = dup(sd);
     125                 :          0 :         repo->sshio.out = dup(sd);
     126                 :          0 :         repo->fh = funopen(repo, ssh_read, ssh_write, NULL, tcp_close);
     127                 :            : 
     128                 :          0 :         retcode = EPKG_FATAL;
     129         [ #  # ]:          0 :         if (repo->fh == NULL) {
     130                 :          0 :                 pkg_emit_errno("Failed to open stream", "tcp_connect");
     131                 :          0 :                 goto tcp_cleanup;
     132                 :            :         }
     133                 :            : 
     134         [ #  # ]:          0 :         if (getline(&line, &linecap, repo->fh) > 0) {
     135         [ #  # ]:          0 :                 if (strncmp(line, "ok:", 3) != 0) {
     136                 :          0 :                         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server rejected, got: %s", line);
     137                 :          0 :                         goto tcp_cleanup;
     138                 :            :                 }
     139                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server is: %s", line +4);
     140                 :          0 :         } else {
     141                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> nothing to read, got: %s", line);
     142                 :          0 :                 goto tcp_cleanup;
     143                 :            :         }
     144                 :          0 :         retcode = EPKG_OK;
     145                 :            : tcp_cleanup:
     146                 :          0 :         if (retcode == EPKG_FATAL && repo->fh != NULL) {
     147                 :          0 :                 fclose(repo->fh);
     148                 :          0 :                 repo->fh = NULL;
     149                 :          0 :         }
     150                 :          0 :         free(line);
     151                 :          0 :         return (retcode);
     152                 :          0 : }
     153                 :            : 
     154                 :            : static int
     155                 :          0 : ssh_connect(struct pkg_repo *repo, struct yuarel *u)
     156                 :            : {
     157                 :          0 :         char *line = NULL;
     158                 :          0 :         size_t linecap = 0;
     159                 :            :         int sshin[2];
     160                 :            :         int sshout[2];
     161                 :          0 :         xstring *cmd = NULL;
     162                 :            :         char *cmdline;
     163                 :          0 :         int retcode = EPKG_FATAL;
     164                 :            :         const char *ssh_args;
     165                 :            :         const char *argv[4];
     166                 :            : 
     167                 :            :         /* Use socket pair because pipe have blocking issues */
     168                 :          0 :         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sshin) <0 ||
     169                 :          0 :                         socketpair(AF_UNIX, SOCK_STREAM, 0, sshout) < 0)
     170                 :          0 :                 return(EPKG_FATAL);
     171                 :            : 
     172                 :          0 :         repo->sshio.pid = fork();
     173         [ #  # ]:          0 :         if (repo->sshio.pid == -1) {
     174                 :          0 :                 pkg_emit_errno("Cannot fork", "start_ssh");
     175                 :          0 :                 goto ssh_cleanup;
     176                 :            :         }
     177                 :            : 
     178                 :          0 :         if (repo->sshio.pid == 0) {
     179                 :            : 
     180                 :          0 :                 if (dup2(sshin[0], STDIN_FILENO) < 0 ||
     181                 :          0 :                                 close(sshin[1]) < 0 ||
     182                 :          0 :                                 close(sshout[0]) < 0 ||
     183                 :          0 :                                 dup2(sshout[1], STDOUT_FILENO) < 0) {
     184                 :          0 :                         pkg_emit_errno("Cannot prepare pipes", "start_ssh");
     185                 :          0 :                         goto ssh_cleanup;
     186                 :            :                 }
     187                 :            : 
     188                 :          0 :                 cmd = xstring_new();
     189                 :          0 :                 fputs("/usr/bin/ssh -e none -T ", cmd->fp);
     190                 :            : 
     191                 :          0 :                 ssh_args = pkg_object_string(pkg_config_get("PKG_SSH_ARGS"));
     192                 :          0 :                 if (ssh_args != NULL)
     193                 :          0 :                         fprintf(cmd->fp, "%s ", ssh_args);
     194         [ #  # ]:          0 :                 if (repo->ip == IPV4)
     195                 :          0 :                         fputs("-4 ", cmd->fp);
     196                 :          0 :                 else if (repo->ip == IPV6)
     197                 :          0 :                         fputs("-6 ", cmd->fp);
     198                 :          0 :                 if (u->port > 0)
     199                 :          0 :                         fprintf(cmd->fp, "-p %d ", u->port);
     200                 :          0 :                 if (u->username != NULL)
     201                 :          0 :                         fprintf(cmd->fp, "%s@", u->username);
     202                 :          0 :                 fprintf(cmd->fp, "%s pkg ssh", u->host);
     203                 :          0 :                 cmdline = xstring_get(cmd);
     204                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "Fetch: running '%s'", cmdline);
     205                 :          0 :                 argv[0] = _PATH_BSHELL;
     206                 :          0 :                 argv[1] = "-c";
     207                 :          0 :                 argv[2] = cmdline;
     208                 :          0 :                 argv[3] = NULL;
     209                 :            : 
     210                 :          0 :                 if (sshin[0] != STDIN_FILENO)
     211                 :          0 :                         close(sshin[0]);
     212                 :          0 :                 if (sshout[1] != STDOUT_FILENO)
     213                 :          0 :                         close(sshout[1]);
     214                 :          0 :                 execvp(argv[0], __DECONST(char **, argv));
     215                 :            :                 /* NOT REACHED */
     216                 :          0 :         }
     217                 :            : 
     218                 :          0 :         if (close(sshout[1]) < 0 || close(sshin[0]) < 0) {
     219                 :          0 :                 pkg_emit_errno("Failed to close pipes", "start_ssh");
     220                 :          0 :                 goto ssh_cleanup;
     221                 :            :         }
     222                 :            : 
     223                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> connected");
     224                 :            : 
     225                 :          0 :         repo->sshio.in = sshout[0];
     226                 :          0 :         repo->sshio.out = sshin[1];
     227                 :          0 :         set_nonblocking(repo->sshio.in);
     228                 :            : 
     229                 :          0 :         repo->fh = funopen(repo, ssh_read, ssh_write, NULL, ssh_close);
     230         [ #  # ]:          0 :         if (repo->fh == NULL) {
     231                 :          0 :                 pkg_emit_errno("Failed to open stream", "start_ssh");
     232                 :          0 :                 goto ssh_cleanup;
     233                 :            :         }
     234                 :            : 
     235         [ #  # ]:          0 :         if (getline(&line, &linecap, repo->fh) > 0) {
     236         [ #  # ]:          0 :                 if (strncmp(line, "ok:", 3) != 0) {
     237                 :          0 :                         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server rejected, got: %s", line);
     238                 :          0 :                         goto ssh_cleanup;
     239                 :            :                 }
     240                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> server is: %s", line +4);
     241                 :          0 :         } else {
     242                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> nothing to read, got: %s", line);
     243                 :          0 :                 goto ssh_cleanup;
     244                 :            :         }
     245                 :          0 :         retcode = EPKG_OK;
     246                 :            : 
     247                 :            : ssh_cleanup:
     248                 :          0 :         if (retcode == EPKG_FATAL && repo->fh != NULL) {
     249                 :          0 :                 fclose(repo->fh);
     250                 :          0 :                 repo->fh = NULL;
     251                 :          0 :         }
     252                 :          0 :         free(line);
     253                 :          0 :         return (retcode);
     254                 :          0 : }
     255                 :            : 
     256                 :            : static int
     257                 :          0 : pkgprotocol_open(struct pkg_repo *repo, struct fetch_item *fi,
     258                 :            :     int (*proto_connect)(struct pkg_repo *, struct yuarel *))
     259                 :            : {
     260                 :          0 :         char *line = NULL;
     261                 :          0 :         size_t linecap = 0;
     262                 :            :         size_t linelen;
     263                 :            :         const char *errstr;
     264                 :          0 :         int retcode = EPKG_FATAL;
     265                 :            :         struct yuarel url;
     266                 :          0 :         char *url_to_free = xstrdup(fi->url);
     267                 :            : 
     268         [ #  # ]:          0 :         if (yuarel_parse(&url, url_to_free) == -1) {
     269                 :          0 :                 free(url_to_free);
     270                 :          0 :                 pkg_emit_error("Invalid url: '%s'", fi->url);
     271                 :          0 :                 return (EPKG_FATAL);
     272                 :            :         }
     273                 :            : 
     274                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> tcp_open");
     275         [ #  # ]:          0 :         if (repo->fh == NULL)
     276                 :          0 :                 retcode = proto_connect(repo, &url);
     277                 :            :         else
     278                 :          0 :                 retcode = EPKG_OK;
     279                 :            : 
     280         [ #  # ]:          0 :         if (retcode != EPKG_OK)
     281                 :          0 :                 return (retcode);
     282                 :            : 
     283                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> get %s %" PRIdMAX "", url.path, (intmax_t)fi->mtime);
     284                 :          0 :         fprintf(repo->fh, "get %s %" PRIdMAX "\n", url.path, (intmax_t)fi->mtime);
     285                 :          0 :         if ((linelen = getline(&line, &linecap, repo->fh)) > 0) {
     286                 :          0 :                 if (line[linelen -1 ] == '\n')
     287                 :          0 :                         line[linelen -1 ] = '\0';
     288                 :            : 
     289                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> recv: %s", line);
     290         [ #  # ]:          0 :                 if (strncmp(line, "ok:", 3) == 0) {
     291                 :          0 :                         fi->size = strtonum(line + 4, 0, LONG_MAX, &errstr);
     292         [ #  # ]:          0 :                         if (errstr) {
     293                 :          0 :                                 goto out;
     294                 :            :                         }
     295                 :            : 
     296         [ #  # ]:          0 :                         if (fi->size == 0) {
     297                 :          0 :                                 retcode = EPKG_UPTODATE;
     298                 :          0 :                                 goto out;
     299                 :            :                         }
     300                 :            : 
     301                 :          0 :                         retcode = EPKG_OK;
     302                 :          0 :                         goto out;
     303                 :            :                 }
     304         [ #  # ]:          0 :                 if (strncmp(line, "ko:", 3) == 0) {
     305                 :          0 :                         retcode = EPKG_FATAL;
     306                 :          0 :                         goto out;
     307                 :            :                 }
     308                 :          0 :         }
     309                 :            : 
     310                 :            : out:
     311                 :          0 :         free(url_to_free);
     312                 :          0 :         free(line);
     313                 :          0 :         return (retcode);
     314                 :          0 : }
     315                 :            : 
     316                 :            : int
     317                 :          0 : tcp_open(struct pkg_repo *repo, struct fetch_item *fi)
     318                 :            : {
     319                 :          0 :         return (pkgprotocol_open(repo, fi, tcp_connect));
     320                 :            : }
     321                 :            : 
     322                 :            : int
     323                 :          0 : ssh_open(struct pkg_repo *repo, struct fetch_item *fi)
     324                 :            : {
     325                 :          0 :         return (pkgprotocol_open(repo, fi, ssh_connect));
     326                 :            : }
     327                 :            : 
     328                 :            : static int
     329                 :          0 : tcp_close(void *data)
     330                 :            : {
     331                 :          0 :         struct pkg_repo *repo = (struct pkg_repo *)data;
     332                 :            : 
     333                 :          0 :         write(repo->sshio.out, "quit\n", 5);
     334                 :          0 :         close(repo->sshio.out);
     335                 :          0 :         close(repo->sshio.in);
     336                 :          0 :         repo->fh = NULL;
     337                 :          0 :         return (0);
     338                 :            : }
     339                 :            : 
     340                 :            : static int
     341                 :          0 : ssh_close(void *data)
     342                 :            : {
     343                 :          0 :         struct pkg_repo *repo = (struct pkg_repo *)data;
     344                 :            :         int pstat;
     345                 :            : 
     346                 :          0 :         write(repo->sshio.out, "quit\n", 5);
     347                 :            : 
     348         [ #  # ]:          0 :         while (waitpid(repo->sshio.pid, &pstat, 0) == -1) {
     349         [ #  # ]:          0 :                 if (errno != EINTR)
     350                 :          0 :                         return (EPKG_FATAL);
     351                 :            :         }
     352                 :          0 :         close(repo->sshio.out);
     353                 :          0 :         close(repo->sshio.in);
     354                 :            : 
     355                 :          0 :         repo->fh = NULL;
     356                 :            : 
     357                 :          0 :         return (WEXITSTATUS(pstat));
     358                 :          0 : }
     359                 :            : 
     360                 :            : static int
     361                 :          0 : ssh_writev(int fd, struct iovec *iov, int iovcnt, int64_t tmout)
     362                 :            : {
     363                 :            :         struct timespec now, timeout, delta;
     364                 :            :         struct pollfd pfd;
     365                 :            :         ssize_t wlen, total;
     366                 :            :         int deltams;
     367                 :            :         struct msghdr msg;
     368                 :            : 
     369                 :          0 :         memset(&pfd, 0, sizeof pfd);
     370                 :            : 
     371                 :          0 :         if (tmout > 0) {
     372                 :          0 :                 pfd.fd = fd;
     373                 :          0 :                 pfd.events = POLLOUT | POLLERR;
     374                 :          0 :                 clock_gettime(CLOCK_REALTIME, &timeout);
     375                 :          0 :                 timeout.tv_sec += tmout;
     376                 :          0 :         }
     377                 :            : 
     378                 :          0 :         total = 0;
     379         [ #  # ]:          0 :         while (iovcnt > 0) {
     380         [ #  # ]:          0 :                 while (tmout && pfd.revents == 0) {
     381                 :          0 :                         clock_gettime(CLOCK_REALTIME, &now);
     382         [ #  # ]:          0 :                         if (!timespeccmp(&timeout, &now, >)) {
     383                 :          0 :                                 errno = ETIMEDOUT;
     384                 :          0 :                                 return (-1);
     385                 :            :                         }
     386                 :          0 :                         timespecsub(&timeout, &now, &delta);
     387                 :          0 :                         deltams = delta.tv_sec * 1000 +
     388                 :          0 :                                 delta.tv_nsec / 1000000;
     389                 :          0 :                         errno = 0;
     390                 :          0 :                         pfd.revents = 0;
     391         [ #  # ]:          0 :                         while (poll(&pfd, 1, deltams) == -1) {
     392         [ #  # ]:          0 :                                 if (errno == EINTR)
     393                 :          0 :                                         continue;
     394                 :            : 
     395                 :          0 :                                 return (-1);
     396                 :            :                         }
     397                 :            :                 }
     398                 :          0 :                 errno = 0;
     399                 :          0 :                 memset(&msg, 0, sizeof(msg));
     400                 :          0 :                 msg.msg_iov = iov;
     401                 :          0 :                 msg.msg_iovlen = iovcnt;
     402                 :            : 
     403                 :          0 :                 wlen = sendmsg(fd, &msg, 0);
     404         [ #  # ]:          0 :                 if (wlen == 0) {
     405                 :          0 :                         errno = ECONNRESET;
     406                 :          0 :                         return (-1);
     407                 :            :                 }
     408         [ #  # ]:          0 :                 else if (wlen < 0)
     409                 :          0 :                         return (-1);
     410                 :            : 
     411                 :          0 :                 total += wlen;
     412                 :            : 
     413         [ #  # ]:          0 :                 while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
     414                 :          0 :                         wlen -= iov->iov_len;
     415                 :          0 :                         iov++;
     416                 :          0 :                         iovcnt--;
     417                 :            :                 }
     418                 :            : 
     419                 :          0 :                 if (iovcnt > 0) {
     420                 :          0 :                         iov->iov_len -= wlen;
     421                 :          0 :                         iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
     422                 :          0 :                 }
     423                 :            :         }
     424                 :          0 :         return (total);
     425                 :          0 : }
     426                 :            : 
     427                 :            : static int
     428                 :          0 : ssh_write(void *data, const char *buf, int l)
     429                 :            : {
     430                 :          0 :         struct pkg_repo *repo = (struct pkg_repo *)data;
     431                 :            :         struct iovec iov;
     432                 :            : 
     433                 :          0 :         iov.iov_base = __DECONST(char *, buf);
     434                 :          0 :         iov.iov_len = l;
     435                 :            : 
     436                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> writing data");
     437                 :            : 
     438                 :          0 :         return (ssh_writev(repo->sshio.out, &iov, 1, repo->fetcher->timeout));
     439                 :            : }
     440                 :            : 
     441                 :            : static int
     442                 :          0 : ssh_read(void *data, char *buf, int len)
     443                 :            : {
     444                 :          0 :         struct pkg_repo *repo = (struct pkg_repo *) data;
     445                 :            :         struct timespec now, timeout, delta;
     446                 :            :         struct pollfd pfd;
     447                 :            :         ssize_t rlen;
     448                 :            :         int deltams;
     449                 :            : 
     450                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> start reading");
     451                 :            : 
     452                 :          0 :         if (repo->fetcher->timeout > 0) {
     453                 :          0 :                 clock_gettime(CLOCK_REALTIME, &timeout);
     454                 :          0 :                 timeout.tv_sec += repo->fetcher->timeout;
     455                 :          0 :         }
     456                 :            : 
     457                 :          0 :         deltams = -1;
     458                 :          0 :         memset(&pfd, 0, sizeof pfd);
     459                 :          0 :         pfd.fd = repo->sshio.in;
     460                 :          0 :         pfd.events = POLLIN | POLLERR;
     461                 :            : 
     462                 :          0 :         for (;;) {
     463                 :          0 :                 rlen = read(pfd.fd, buf, len);
     464                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 1, "SSH> read %jd", (intmax_t)rlen);
     465         [ #  # ]:          0 :                 if (rlen >= 0) {
     466                 :          0 :                         break;
     467                 :          0 :                 } else if (rlen == -1) {
     468         [ #  # ]:          0 :                         if (errno == EINTR)
     469                 :          0 :                                 continue;
     470         [ #  # ]:          0 :                         if (errno != EAGAIN) {
     471                 :          0 :                                 pkg_emit_errno("timeout", "ssh");
     472                 :          0 :                                 return (-1);
     473                 :            :                         }
     474                 :          0 :                 }
     475                 :            : 
     476                 :            :                 /* only EAGAIN should get here */
     477                 :          0 :                 if (repo->fetcher->timeout > 0) {
     478                 :          0 :                         clock_gettime(CLOCK_REALTIME, &now);
     479         [ #  # ]:          0 :                         if (!timespeccmp(&timeout, &now, >)) {
     480                 :          0 :                                 errno = ETIMEDOUT;
     481                 :          0 :                                 return (-1);
     482                 :            :                         }
     483                 :          0 :                         timespecsub(&timeout, &now, &delta);
     484                 :          0 :                         deltams = delta.tv_sec * 1000 +
     485                 :          0 :                             delta.tv_nsec / 1000000;
     486                 :          0 :                 }
     487                 :            : 
     488                 :          0 :                 errno = 0;
     489                 :          0 :                 pfd.revents = 0;
     490                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 2, "SSH> begin poll()");
     491         [ #  # ]:          0 :                 if (poll(&pfd, 1, deltams) < 0) {
     492         [ #  # ]:          0 :                         if (errno == EINTR)
     493                 :          0 :                                 continue;
     494                 :          0 :                         return (-1);
     495                 :            :                 }
     496                 :          0 :                 pkg_dbg(PKG_DBG_FETCH, 2, "SSH> end poll()");
     497                 :            : 
     498                 :            :         }
     499                 :            : 
     500                 :          0 :         pkg_dbg(PKG_DBG_FETCH, 1, "SSH> have read %jd bytes", (intmax_t)rlen);
     501                 :            : 
     502                 :          0 :         return (rlen);
     503                 :          0 : }

Generated by: LCOV version 1.15