LCOV - code coverage report
Current view: top level - libpkg - fetch.c (source / functions) Hit Total Coverage
Test: cov.info Lines: 79 371 21.3 %
Date: 2015-08-15 Functions: 1 9 11.1 %

          Line data    Source code
       1             : /*-
       2             :  * Copyright (c) 2012-2013 Baptiste Daroussin <bapt@FreeBSD.org>
       3             :  * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
       4             :  * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
       5             :  * All rights reserved.
       6             :  * 
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, this list of conditions and the following disclaimer
      12             :  *    in this position and unchanged.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 
      17             :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      18             :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      19             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      20             :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      21             :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      22             :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      23             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      24             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      25             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      26             :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      27             :  */
      28             : 
      29             : #include <sys/param.h>
      30             : #include <sys/wait.h>
      31             : #include <sys/socket.h>
      32             : #include <sys/time.h>
      33             : 
      34             : #include <ctype.h>
      35             : #include <fcntl.h>
      36             : #include <errno.h>
      37             : #define _WITH_GETLINE
      38             : #include <stdio.h>
      39             : #include <string.h>
      40             : #include <fetch.h>
      41             : #include <paths.h>
      42             : #include <poll.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/utils.h"
      50             : 
      51             : static void
      52           0 : gethttpmirrors(struct pkg_repo *repo, const char *url) {
      53             :         FILE *f;
      54           0 :         char *line = NULL;
      55           0 :         size_t linecap = 0;
      56             :         ssize_t linelen;
      57             :         struct http_mirror *m;
      58             :         struct url *u;
      59             : 
      60           0 :         if ((f = fetchGetURL(url, "")) == NULL)
      61           0 :                 return;
      62             : 
      63           0 :         while ((linelen = getline(&line, &linecap, f)) > 0) {
      64           0 :                 if (strncmp(line, "URL:", 4) == 0) {
      65             :                         /* trim '\n' */
      66           0 :                         if (line[linelen - 1] == '\n')
      67           0 :                                 line[linelen - 1 ] = '\0';
      68             : 
      69           0 :                         line += 4;
      70           0 :                         while (isspace(*line)) {
      71           0 :                                 line++;
      72             :                         }
      73           0 :                         if (*line == '\0')
      74           0 :                                 continue;
      75             : 
      76           0 :                         if ((u = fetchParseURL(line)) != NULL) {
      77           0 :                                 m = malloc(sizeof(struct http_mirror));
      78           0 :                                 m->url = u;
      79           0 :                                 LL_APPEND(repo->http, m);
      80             :                         }
      81             :                 }
      82             :         }
      83           0 :         fclose(f);
      84           0 :         return;
      85             : }
      86             : 
      87             : int
      88           0 : pkg_fetch_file_tmp(struct pkg_repo *repo, const char *url, char *dest,
      89             :         time_t t)
      90             : {
      91           0 :         int fd = -1;
      92           0 :         int retcode = EPKG_FATAL;
      93             : 
      94           0 :         fd = mkstemp(dest);
      95             : 
      96           0 :         if (fd == -1) {
      97           0 :                 pkg_emit_errno("mkstemp", dest);
      98           0 :                 return(EPKG_FATAL);
      99             :         }
     100             : 
     101           0 :         retcode = pkg_fetch_file_to_fd(repo, url, fd, &t, 0, -1);
     102             : 
     103           0 :         if (t != 0) {
     104           0 :                 struct timeval ftimes[2] = {
     105             :                         {
     106             :                         .tv_sec = t,
     107             :                         .tv_usec = 0
     108             :                         },
     109             :                         {
     110             :                         .tv_sec = t,
     111             :                         .tv_usec = 0
     112             :                         }
     113             :                 };
     114           0 :                 futimes(fd, ftimes);
     115             :         }
     116             : 
     117           0 :         close(fd);
     118             : 
     119             :         /* Remove local file if fetch failed */
     120           0 :         if (retcode != EPKG_OK)
     121           0 :                 unlink(dest);
     122             : 
     123           0 :         return (retcode);
     124             : }
     125             : 
     126             : int
     127           0 : pkg_fetch_file(struct pkg_repo *repo, const char *url, char *dest, time_t t,
     128             :     ssize_t offset, int64_t size)
     129             : {
     130           0 :         int fd = -1;
     131           0 :         int retcode = EPKG_FATAL;
     132             : 
     133           0 :         fd = open(dest, O_CREAT|O_APPEND|O_WRONLY, 00644);
     134           0 :         if (fd == -1) {
     135           0 :                 pkg_emit_errno("open", dest);
     136           0 :                 return(EPKG_FATAL);
     137             :         }
     138             : 
     139           0 :         retcode = pkg_fetch_file_to_fd(repo, url, fd, &t, offset, size);
     140             : 
     141           0 :         if (t != 0) {
     142           0 :                 struct timeval ftimes[2] = {
     143             :                         {
     144             :                         .tv_sec = t,
     145             :                         .tv_usec = 0
     146             :                         },
     147             :                         {
     148             :                         .tv_sec = t,
     149             :                         .tv_usec = 0
     150             :                         }
     151             :                 };
     152           0 :                 futimes(fd, ftimes);
     153             :         }
     154             : 
     155           0 :         close(fd);
     156             : 
     157             :         /* Remove local file if fetch failed */
     158           0 :         if (retcode != EPKG_OK)
     159           0 :                 unlink(dest);
     160             : 
     161           0 :         return (retcode);
     162             : }
     163             : 
     164             : static int
     165           0 : ssh_read(void *data, char *buf, int len)
     166             : {
     167           0 :         struct pkg_repo *repo = (struct pkg_repo *) data;
     168             :         struct timeval now, timeout, delta;
     169             :         struct pollfd pfd;
     170             :         ssize_t rlen;
     171             :         int deltams;
     172             : 
     173           0 :         pkg_debug(2, "ssh: start reading %d");
     174             : 
     175           0 :         if (fetchTimeout > 0) {
     176           0 :                 gettimeofday(&timeout, NULL);
     177           0 :                 timeout.tv_sec += fetchTimeout;
     178             :         }
     179             : 
     180           0 :         deltams = -1;
     181           0 :         memset(&pfd, 0, sizeof pfd);
     182           0 :         pfd.fd = repo->sshio.in;
     183           0 :         pfd.events = POLLIN | POLLERR;
     184             : 
     185             :         for (;;) {
     186           0 :                 rlen = read(pfd.fd, buf, len);
     187           0 :                 pkg_debug(2, "read %d", rlen);
     188           0 :                 if (rlen >= 0) {
     189           0 :                         break;
     190           0 :                 } else if (rlen == -1) {
     191           0 :                         if (errno == EINTR)
     192           0 :                                 continue;
     193           0 :                         if (errno != EAGAIN) {
     194           0 :                                 pkg_emit_errno("timeout", "ssh");
     195           0 :                                 return (-1);
     196             :                         }
     197             :                 }
     198             : 
     199             :                 /* only EAGAIN should get here */
     200           0 :                 if (fetchTimeout > 0) {
     201           0 :                         gettimeofday(&now, NULL);
     202           0 :                         if (!timercmp(&timeout, &now, >)) {
     203           0 :                                 errno = ETIMEDOUT;
     204           0 :                                 return (-1);
     205             :                         }
     206           0 :                         timersub(&timeout, &now, &delta);
     207           0 :                         deltams = delta.tv_sec * 1000 +
     208           0 :                             delta.tv_usec / 1000;
     209             :                 }
     210             : 
     211           0 :                 errno = 0;
     212           0 :                 pfd.revents = 0;
     213           0 :                 pkg_debug(1, "begin poll()");
     214           0 :                 if (poll(&pfd, 1, deltams) < 0) {
     215           0 :                         if (errno == EINTR)
     216           0 :                                 continue;
     217           0 :                         return (-1);
     218             :                 }
     219           0 :                 pkg_debug(1, "end poll()");
     220             : 
     221             : 
     222           0 :         }
     223             : 
     224           0 :         pkg_debug(2, "ssh: have read %d bytes", rlen);
     225             : 
     226           0 :         return (rlen);
     227             : }
     228             : 
     229             : static int
     230           0 : ssh_writev(int fd, struct iovec *iov, int iovcnt)
     231             : {
     232             :         struct timeval now, timeout, delta;
     233             :         struct pollfd pfd;
     234             :         ssize_t wlen, total;
     235             :         int deltams;
     236             :         struct msghdr msg;
     237             : 
     238           0 :         memset(&pfd, 0, sizeof pfd);
     239             : 
     240           0 :         if (fetchTimeout) {
     241           0 :                 pfd.fd = fd;
     242           0 :                 pfd.events = POLLOUT | POLLERR;
     243           0 :                 gettimeofday(&timeout, NULL);
     244           0 :                 timeout.tv_sec += fetchTimeout;
     245             :         }
     246             : 
     247           0 :         total = 0;
     248           0 :         while (iovcnt > 0) {
     249           0 :                 while (fetchTimeout && pfd.revents == 0) {
     250           0 :                         gettimeofday(&now, NULL);
     251           0 :                         if (!timercmp(&timeout, &now, >)) {
     252           0 :                                 errno = ETIMEDOUT;
     253           0 :                                 return (-1);
     254             :                         }
     255           0 :                         timersub(&timeout, &now, &delta);
     256           0 :                         deltams = delta.tv_sec * 1000 +
     257           0 :                                 delta.tv_usec / 1000;
     258           0 :                         errno = 0;
     259           0 :                         pfd.revents = 0;
     260           0 :                         while (poll(&pfd, 1, deltams) == -1) {
     261           0 :                                 if (errno == EINTR)
     262           0 :                                         continue;
     263             : 
     264           0 :                                 return (-1);
     265             :                         }
     266             :                 }
     267           0 :                 errno = 0;
     268           0 :                 memset(&msg, 0, sizeof(msg));
     269           0 :                 msg.msg_iov = iov;
     270           0 :                 msg.msg_iovlen = iovcnt;
     271             : 
     272           0 :                 wlen = sendmsg(fd, &msg, 0);
     273           0 :                 if (wlen == 0) {
     274           0 :                         errno = ECONNRESET;
     275           0 :                         return (-1);
     276             :                 }
     277           0 :                 else if (wlen < 0)
     278           0 :                         return (-1);
     279             : 
     280           0 :                 total += wlen;
     281             : 
     282           0 :                 while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
     283           0 :                         wlen -= iov->iov_len;
     284           0 :                         iov++;
     285           0 :                         iovcnt--;
     286             :                 }
     287             : 
     288           0 :                 if (iovcnt > 0) {
     289           0 :                         iov->iov_len -= wlen;
     290           0 :                         iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
     291             :                 }
     292             :         }
     293           0 :         return (total);
     294             : }
     295             : 
     296             : static int
     297           0 : ssh_write(void *data, const char *buf, int l)
     298             : {
     299           0 :         struct pkg_repo *repo = (struct pkg_repo *)data;
     300             :         struct iovec iov;
     301             : 
     302           0 :         iov.iov_base = __DECONST(char *, buf);
     303           0 :         iov.iov_len = l;
     304             : 
     305           0 :         pkg_debug(1, "writing data");
     306             : 
     307           0 :         return (ssh_writev(repo->sshio.out, &iov, 1));
     308             : }
     309             : 
     310             : static int
     311           0 : ssh_close(void *data)
     312             : {
     313           0 :         struct pkg_repo *repo = (struct pkg_repo *)data;
     314             :         int pstat;
     315             : 
     316           0 :         write(repo->sshio.out, "quit\n", 5);
     317             : 
     318           0 :         while (waitpid(repo->sshio.pid, &pstat, 0) == -1) {
     319           0 :                 if (errno != EINTR)
     320           0 :                         return (EPKG_FATAL);
     321             :         }
     322             : 
     323           0 :         repo->ssh = NULL;
     324             : 
     325           0 :         return (WEXITSTATUS(pstat));
     326             : }
     327             : 
     328             : static int
     329           0 : start_ssh(struct pkg_repo *repo, struct url *u, off_t *sz)
     330             : {
     331           0 :         char *line = NULL;
     332           0 :         size_t linecap = 0;
     333             :         size_t linelen;
     334           0 :         struct sbuf *cmd = NULL;
     335             :         const char *errstr;
     336             :         const char *ssh_args;
     337             :         int sshin[2];
     338             :         int sshout[2];
     339             :         const char *argv[4];
     340             : 
     341           0 :         ssh_args = pkg_object_string(pkg_config_get("PKG_SSH_ARGS"));
     342             : 
     343           0 :         if (repo->ssh == NULL) {
     344             :                 /* Use socket pair because pipe have blocking issues */
     345           0 :                 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sshin) <0 ||
     346           0 :                     socketpair(AF_UNIX, SOCK_STREAM, 0, sshout) < 0)
     347           0 :                         return(EPKG_FATAL);
     348             : 
     349           0 :                 repo->sshio.pid = fork();
     350           0 :                 if (repo->sshio.pid == -1) {
     351           0 :                         pkg_emit_errno("Cannot fork", "start_ssh");
     352           0 :                         return (EPKG_FATAL);
     353             :                 }
     354             : 
     355           0 :                 if (repo->sshio.pid == 0) {
     356           0 :                         if (dup2(sshin[0], STDIN_FILENO) < 0 ||
     357           0 :                             close(sshin[1]) < 0 ||
     358           0 :                             close(sshout[0]) < 0 ||
     359           0 :                             dup2(sshout[1], STDOUT_FILENO) < 0) {
     360           0 :                                 pkg_emit_errno("Cannot prepare pipes", "start_ssh");
     361           0 :                                 return (EPKG_FATAL);
     362             :                         }
     363             : 
     364           0 :                         cmd = sbuf_new_auto();
     365           0 :                         sbuf_cat(cmd, "/usr/bin/ssh -e none -T ");
     366           0 :                         if (ssh_args != NULL)
     367           0 :                                 sbuf_printf(cmd, "%s ", ssh_args);
     368           0 :                         if ((repo->flags & REPO_FLAGS_USE_IPV4) == REPO_FLAGS_USE_IPV4)
     369           0 :                                 sbuf_cat(cmd, "-4 ");
     370           0 :                         else if ((repo->flags & REPO_FLAGS_USE_IPV6) == REPO_FLAGS_USE_IPV6)
     371           0 :                                 sbuf_cat(cmd, "-6 ");
     372           0 :                         if (u->port > 0)
     373           0 :                                 sbuf_printf(cmd, "-p %d ", u->port);
     374           0 :                         if (u->user[0] != '\0')
     375           0 :                                 sbuf_printf(cmd, "%s@", u->user);
     376           0 :                         sbuf_cat(cmd, u->host);
     377           0 :                         sbuf_printf(cmd, " pkg ssh");
     378           0 :                         sbuf_finish(cmd);
     379           0 :                         pkg_debug(1, "Fetch: running '%s'", sbuf_data(cmd));
     380           0 :                         argv[0] = _PATH_BSHELL;
     381           0 :                         argv[1] = "-c";
     382           0 :                         argv[2] = sbuf_data(cmd);
     383           0 :                         argv[3] = NULL;
     384             : 
     385           0 :                         if (sshin[0] != STDIN_FILENO)
     386           0 :                                 close(sshin[0]);
     387           0 :                         if (sshout[1] != STDOUT_FILENO)
     388           0 :                                 close(sshout[1]);
     389           0 :                         execvp(argv[0], __DECONST(char **, argv));
     390             :                         /* NOT REACHED */
     391             :                 }
     392             : 
     393           0 :                 if (close(sshout[1]) < 0 || close(sshin[0]) < 0) {
     394           0 :                         pkg_emit_errno("Failed to close pipes", "start_ssh");
     395           0 :                         return (EPKG_FATAL);
     396             :                 }
     397             : 
     398           0 :                 pkg_debug(1, "SSH> connected");
     399             : 
     400           0 :                 repo->sshio.in = sshout[0];
     401           0 :                 repo->sshio.out = sshin[1];
     402           0 :                 set_nonblocking(repo->sshio.in);
     403             : 
     404           0 :                 repo->ssh = funopen(repo, ssh_read, ssh_write, NULL, ssh_close);
     405           0 :                 if (repo->ssh == NULL) {
     406           0 :                         pkg_emit_errno("Failed to open stream", "start_ssh");
     407           0 :                         return (EPKG_FATAL);
     408             :                 }
     409             : 
     410           0 :                 if (getline(&line, &linecap, repo->ssh) > 0) {
     411           0 :                         if (strncmp(line, "ok:", 3) != 0) {
     412           0 :                                 pkg_debug(1, "SSH> server rejected, got: %s", line);
     413           0 :                                 fclose(repo->ssh);
     414           0 :                                 free(line);
     415           0 :                                 return (EPKG_FATAL);
     416             :                         }
     417           0 :                         pkg_debug(1, "SSH> server is: %s", line +4);
     418             :                 } else {
     419           0 :                         pkg_debug(1, "SSH> nothing to read, got: %s", line);
     420           0 :                         fclose(repo->ssh);
     421           0 :                         return (EPKG_FATAL);
     422             :                 }
     423             :         }
     424           0 :         pkg_debug(1, "SSH> get %s %" PRIdMAX "", u->doc, (intmax_t)u->ims_time);
     425           0 :         fprintf(repo->ssh, "get %s %" PRIdMAX "\n", u->doc, (intmax_t)u->ims_time);
     426           0 :         if ((linelen = getline(&line, &linecap, repo->ssh)) > 0) {
     427           0 :                 if (line[linelen -1 ] == '\n')
     428           0 :                         line[linelen -1 ] = '\0';
     429             : 
     430           0 :                 pkg_debug(1, "SSH> recv: %s", line);
     431           0 :                 if (strncmp(line, "ok:", 3) == 0) {
     432           0 :                         *sz = strtonum(line + 4, 0, LONG_MAX, &errstr);
     433           0 :                         if (errstr) {
     434           0 :                                 free(line);
     435           0 :                                 return (EPKG_FATAL);
     436             :                         }
     437             : 
     438           0 :                         if (*sz == 0) {
     439           0 :                                 free(line);
     440           0 :                                 return (EPKG_UPTODATE);
     441             :                         }
     442             : 
     443           0 :                         free(line);
     444           0 :                         return (EPKG_OK);
     445             :                 }
     446             : 
     447             :         }
     448             : 
     449           0 :         free(line);
     450           0 :         return (EPKG_FATAL);
     451             : }
     452             : 
     453             : #define URL_SCHEME_PREFIX       "pkg+"
     454             : 
     455             : int
     456          16 : pkg_fetch_file_to_fd(struct pkg_repo *repo, const char *url, int dest,
     457             :     time_t *t, ssize_t offset, int64_t size)
     458             : {
     459          16 :         FILE            *remote = NULL;
     460          16 :         struct url      *u = NULL;
     461             :         struct url_stat  st;
     462          16 :         off_t            done = 0;
     463             :         off_t            r;
     464             :         int64_t          max_retry, retry;
     465             :         int64_t          fetch_timeout;
     466             :         char             buf[10240];
     467          16 :         char            *doc = NULL;
     468             :         char             docpath[MAXPATHLEN];
     469          16 :         int              retcode = EPKG_OK;
     470             :         char             zone[MAXHOSTNAMELEN + 13];
     471          16 :         struct dns_srvinfo      *srv_current = NULL;
     472          16 :         struct http_mirror      *http_current = NULL;
     473          16 :         off_t            sz = 0;
     474          16 :         size_t           buflen = 0;
     475          16 :         size_t           left = 0;
     476          16 :         bool             pkg_url_scheme = false;
     477          16 :         struct sbuf     *fetchOpts = NULL;
     478             : 
     479          16 :         max_retry = pkg_object_int(pkg_config_get("FETCH_RETRY"));
     480          16 :         fetch_timeout = pkg_object_int(pkg_config_get("FETCH_TIMEOUT"));
     481             : 
     482          16 :         fetchTimeout = (int) fetch_timeout;
     483             : 
     484          16 :         retry = max_retry;
     485             : 
     486             :         /* A URL of the form http://host.example.com/ where
     487             :          * host.example.com does not resolve as a simple A record is
     488             :          * not valid according to RFC 2616 Section 3.2.2.  Our usage
     489             :          * with SRV records is incorrect.  However it is encoded into
     490             :          * /usr/sbin/pkg in various releases so we can't just drop it.
     491             :          *
     492             :          * Instead, introduce new pkg+http://, pkg+https://,
     493             :          * pkg+ssh://, pkg+ftp://, pkg+file:// to support the
     494             :          * SRV-style server discovery, and also to allow eg. Firefox
     495             :          * to run pkg-related stuff given a pkg+foo:// URL.
     496             :          *
     497             :          * Error if using plain http://, https:// etc with SRV
     498             :          */
     499             : 
     500          32 :         if (repo != NULL &&
     501          16 :                 strncmp(URL_SCHEME_PREFIX, url, strlen(URL_SCHEME_PREFIX)) == 0) {
     502           0 :                 if (repo->mirror_type != SRV) {
     503           0 :                         pkg_emit_error("packagesite URL error for %s -- "
     504             :                                        URL_SCHEME_PREFIX
     505             :                                        ":// implies SRV mirror type", url);
     506             : 
     507             :                         /* Too early for there to be anything to cleanup */
     508           0 :                         return(EPKG_FATAL);
     509             :                 }
     510             : 
     511           0 :                 url += strlen(URL_SCHEME_PREFIX);
     512           0 :                 pkg_url_scheme = true;
     513             :         }
     514             : 
     515          16 :         u = fetchParseURL(url);
     516          16 :         if (t != NULL)
     517          16 :                 u->ims_time = *t;
     518             : 
     519          16 :         if (repo != NULL && strcmp(u->scheme, "ssh") == 0) {
     520           0 :                 if ((retcode = start_ssh(repo, u, &sz)) != EPKG_OK)
     521           0 :                         goto cleanup;
     522           0 :                 remote = repo->ssh;
     523             :         }
     524             : 
     525          16 :         doc = u->doc;
     526          48 :         while (remote == NULL) {
     527          16 :                 if (retry == max_retry) {
     528          16 :                         if (repo != NULL && repo->mirror_type == SRV &&
     529           0 :                             (strncmp(u->scheme, "http", 4) == 0
     530           0 :                              || strcmp(u->scheme, "ftp") == 0)) {
     531             : 
     532           0 :                                 if (!pkg_url_scheme)
     533           0 :                                         pkg_emit_notice(
     534             :      "Warning: use of %s:// URL scheme with SRV records is deprecated: "
     535           0 :      "switch to pkg+%s://", u->scheme, u->scheme);
     536             : 
     537           0 :                                 snprintf(zone, sizeof(zone),
     538           0 :                                     "_%s._tcp.%s", u->scheme, u->host);
     539           0 :                                 if (repo->srv == NULL)
     540           0 :                                         repo->srv = dns_getsrvinfo(zone);
     541           0 :                                 srv_current = repo->srv;
     542          16 :                         } else if (repo != NULL && repo->mirror_type == HTTP &&
     543           0 :                                    strncmp(u->scheme, "http", 4) == 0) {
     544           0 :                                 snprintf(zone, sizeof(zone),
     545           0 :                                     "%s://%s", u->scheme, u->host);
     546           0 :                                 if (repo->http == NULL)
     547           0 :                                         gethttpmirrors(repo, zone);
     548           0 :                                 http_current = repo->http;
     549             :                         }
     550             :                 }
     551             : 
     552          16 :                 if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
     553           0 :                         strlcpy(u->host, srv_current->host, sizeof(u->host));
     554           0 :                         u->port = srv_current->port;
     555             :                 }
     556          16 :                 else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
     557           0 :                         strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme));
     558           0 :                         strlcpy(u->host, http_current->url->host, sizeof(u->host));
     559           0 :                         snprintf(docpath, sizeof(docpath), "%s%s", http_current->url->doc, doc);
     560           0 :                         u->doc = docpath;
     561           0 :                         u->port = http_current->url->port;
     562             :                 }
     563             : 
     564          16 :                 fetchOpts = sbuf_new_auto();
     565          16 :                 sbuf_cat(fetchOpts, "i");
     566          16 :                 if (repo != NULL) {
     567          16 :                         if ((repo->flags & REPO_FLAGS_USE_IPV4) ==
     568             :                             REPO_FLAGS_USE_IPV4)
     569           0 :                                 sbuf_cat(fetchOpts, "4");
     570          16 :                         else if ((repo->flags & REPO_FLAGS_USE_IPV6) ==
     571             :                             REPO_FLAGS_USE_IPV6)
     572           0 :                                 sbuf_cat(fetchOpts, "6");
     573             :                 }
     574             : 
     575          48 :                 pkg_debug(1,"Fetch: fetching from: %s://%s%s%s%s with opts \"%s\"",
     576          16 :                     u->scheme,
     577          16 :                     u->user,
     578          16 :                     u->user[0] != '\0' ? "@" : "",
     579          16 :                     u->host,
     580             :                     u->doc,
     581             :                     sbuf_data(fetchOpts));
     582             : 
     583          16 :                 sbuf_finish(fetchOpts);
     584             : 
     585          16 :                 if (offset > 0)
     586           0 :                         u->offset = offset;
     587          16 :                 remote = fetchXGet(u, &st, sbuf_data(fetchOpts));
     588          16 :                 if (remote == NULL) {
     589           0 :                         if (fetchLastErrCode == FETCH_OK) {
     590           0 :                                 retcode = EPKG_UPTODATE;
     591           0 :                                 goto cleanup;
     592             :                         }
     593           0 :                         --retry;
     594           0 :                         if (retry <= 0 || fetchLastErrCode == FETCH_UNAVAIL) {
     595           0 :                                 pkg_emit_error("%s: %s", url,
     596             :                                     fetchLastErrString);
     597           0 :                                 retcode = EPKG_FATAL;
     598           0 :                                 goto cleanup;
     599             :                         }
     600           0 :                         if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
     601           0 :                                 srv_current = srv_current->next;
     602           0 :                                 if (srv_current == NULL)
     603           0 :                                         srv_current = repo->srv;
     604           0 :                         } else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
     605           0 :                                 http_current = repo->http->next;
     606           0 :                                 if (http_current == NULL)
     607           0 :                                         http_current = repo->http;
     608             :                         } else {
     609           0 :                                 sleep(1);
     610             :                         }
     611             :                 }
     612             :         }
     613             : 
     614          16 :         if (strcmp(u->scheme, "ssh") != 0) {
     615          16 :                 if (t != NULL && st.mtime != 0) {
     616          16 :                         if (st.mtime <= *t) {
     617           2 :                                 retcode = EPKG_UPTODATE;
     618           2 :                                 goto cleanup;
     619             :                         } else
     620          14 :                                 *t = st.mtime;
     621             :                 }
     622          14 :                 sz = st.size;
     623             :         }
     624             : 
     625          14 :         if (sz <= 0 && size > 0)
     626           0 :                 sz = size;
     627             : 
     628          14 :         pkg_emit_fetch_begin(url);
     629          14 :         pkg_emit_progress_start(NULL);
     630          14 :         if (offset > 0)
     631           0 :                 done += offset;
     632          14 :         buflen = sizeof(buf);
     633          14 :         left = sizeof(buf);
     634          14 :         if (sz > 0)
     635          14 :                 left = sz - done;
     636          42 :         while ((r = fread(buf, 1, left < buflen ? left : buflen, remote)) > 0) {
     637          14 :                 if (write(dest, buf, r) != r) {
     638           0 :                         pkg_emit_errno("write", "");
     639           0 :                         retcode = EPKG_FATAL;
     640           0 :                         goto cleanup;
     641             :                 }
     642          14 :                 done += r;
     643          14 :                 if (sz > 0) {
     644          14 :                         left -= r;
     645          14 :                         pkg_debug(1, "Read status: %d over %d", done, sz);
     646             :                 } else
     647           0 :                         pkg_debug(1, "Read status: %d", done);
     648          14 :                 if (sz > 0)
     649          14 :                         pkg_emit_progress_tick(done, sz);
     650             :         }
     651             : 
     652          14 :         if (r != 0) {
     653           0 :                 pkg_emit_error("An error occurred while fetching package");
     654           0 :                 retcode = EPKG_FATAL;
     655           0 :                 goto cleanup;
     656             :         } else {
     657          14 :                 pkg_emit_progress_tick(done, done);
     658             :         }
     659          14 :         pkg_emit_fetch_finished(url);
     660             : 
     661          14 :         if (strcmp(u->scheme, "ssh") != 0 && ferror(remote)) {
     662           0 :                 pkg_emit_error("%s: %s", url, fetchLastErrString);
     663           0 :                 retcode = EPKG_FATAL;
     664           0 :                 goto cleanup;
     665             :         }
     666             : 
     667             : cleanup:
     668          16 :         if (u != NULL) {
     669          16 :                 if (remote != NULL &&  repo != NULL && remote != repo->ssh)
     670          16 :                         fclose(remote);
     671             :         }
     672             : 
     673             :         /* restore original doc */
     674          16 :         u->doc = doc;
     675          16 :         if (fetchOpts != NULL)
     676          16 :                 sbuf_delete(fetchOpts);
     677             : 
     678          16 :         fetchFreeURL(u);
     679             : 
     680          16 :         return (retcode);
     681             : }

Generated by: LCOV version 1.10