LCOV - code coverage report
Current view: top level - libpkg - fetch_libfetch.c (source / functions) Hit Total Coverage
Test: rapport Lines: 62 142 43.7 %
Date: 2021-12-10 16:22:55 Functions: 2 3 66.7 %
Branches: 30 104 28.8 %

           Branch data     Line data    Source code
       1                 :            : /*-
       2                 :            :  * Copyright (c) 2020 Baptiste Daroussin <bapt@FreeBSD.org>
       3                 :            :  *
       4                 :            :  * Redistribution and use in source and binary forms, with or without
       5                 :            :  * modification, are permitted provided that the following conditions
       6                 :            :  * are met:
       7                 :            :  * 1. Redistributions of source code must retain the above copyright
       8                 :            :  *    notice, this list of conditions and the following disclaimer
       9                 :            :  *    in this position and unchanged.
      10                 :            :  * 2. Redistributions in binary form must reproduce the above copyright
      11                 :            :  *    notice, this list of conditions and the following disclaimer in the
      12                 :            :  *    documentation and/or other materials provided with the distribution.
      13                 :            :  *
      14                 :            :  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
      15                 :            :  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      16                 :            :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
      17                 :            :  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
      18                 :            :  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
      19                 :            :  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      20                 :            :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      21                 :            :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      22                 :            :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
      23                 :            :  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      24                 :            :  */
      25                 :            : 
      26                 :            : 
      27                 :            : #include <sys/param.h>
      28                 :            : #include <sys/wait.h>
      29                 :            : #include <sys/socket.h>
      30                 :            : #include <sys/time.h>
      31                 :            : 
      32                 :            : #include <ctype.h>
      33                 :            : #include <fcntl.h>
      34                 :            : #include <errno.h>
      35                 :            : #include <stdio.h>
      36                 :            : #include <string.h>
      37                 :            : #include <fetch.h>
      38                 :            : #include <paths.h>
      39                 :            : #include <poll.h>
      40                 :            : #include <xstring.h>
      41                 :            : 
      42                 :            : #include <bsd_compat.h>
      43                 :            : 
      44                 :            : #include "pkg.h"
      45                 :            : #include "private/event.h"
      46                 :            : #include "private/pkg.h"
      47                 :            : #include "private/fetch.h"
      48                 :            : #include "private/utils.h"
      49                 :            : 
      50                 :            : static void
      51                 :          0 : gethttpmirrors(struct pkg_repo *repo, const char *url, bool withdoc) {
      52                 :            :         FILE *f;
      53                 :          0 :         char *line = NULL, *walk;
      54                 :          0 :         size_t linecap = 0;
      55                 :            :         ssize_t linelen;
      56                 :            :         struct http_mirror *m;
      57                 :            :         struct url *u;
      58                 :            : 
      59         [ #  # ]:          0 :         if ((f = fetchGetURL(url, "")) == NULL)
      60                 :          0 :                 return;
      61                 :            : 
      62         [ #  # ]:          0 :         while ((linelen = getline(&line, &linecap, f)) > 0) {
      63         [ #  # ]:          0 :                 if (strncmp(line, "URL:", 4) == 0) {
      64                 :          0 :                         walk = line;
      65                 :            :                         /* trim '\n' */
      66         [ #  # ]:          0 :                         if (walk[linelen - 1] == '\n')
      67                 :          0 :                                 walk[linelen - 1 ] = '\0';
      68                 :            : 
      69                 :          0 :                         walk += 4;
      70         [ #  # ]:          0 :                         while (isspace(*walk)) {
      71                 :          0 :                                 walk++;
      72                 :            :                         }
      73         [ #  # ]:          0 :                         if (*walk == '\0')
      74                 :          0 :                                 continue;
      75                 :            : 
      76         [ #  # ]:          0 :                         if ((u = fetchParseURL(walk)) != NULL) {
      77                 :          0 :                                 m = xmalloc(sizeof(struct http_mirror));
      78                 :          0 :                                 m->reldoc = withdoc;
      79                 :          0 :                                 m->url = u;
      80   [ #  #  #  # ]:          0 :                                 LL_APPEND(repo->http, m);
      81                 :          0 :                         }
      82                 :          0 :                 }
      83                 :            :         }
      84                 :            : 
      85                 :          0 :         free(line);
      86                 :          0 :         fclose(f);
      87                 :          0 :         return;
      88                 :          0 : }
      89                 :            : 
      90                 :            : static int
      91                 :         28 : fetch_connect(struct pkg_repo *repo, struct url *u)
      92                 :            : {
      93                 :            :         struct url *repourl;
      94                 :         28 :         xstring *fetchOpts = NULL;
      95                 :            :         int64_t max_retry, retry;
      96                 :            :         int64_t fetch_timeout;
      97                 :         28 :         int retcode = EPKG_OK;
      98                 :            :         char docpath[MAXPATHLEN];
      99                 :            :         char zone[MAXHOSTNAMELEN + 24];
     100                 :            :         char *doc, *reldoc, *opts;
     101                 :         28 :         struct dns_srvinfo *srv_current = NULL;
     102                 :         28 :         struct http_mirror *http_current = NULL;
     103                 :            :         struct url_stat st;
     104                 :            : 
     105                 :         28 :         max_retry = pkg_object_int(pkg_config_get("FETCH_RETRY"));
     106                 :         28 :         fetch_timeout = pkg_object_int(pkg_config_get("FETCH_TIMEOUT"));
     107                 :            : 
     108                 :         28 :         fetchConnectionCacheInit(-1, -1);
     109         [ +  - ]:         28 :         fetchTimeout = (int)MIN(fetch_timeout, INT_MAX);
     110                 :            : 
     111                 :         28 :         repourl = fetchParseURL(repo->url);
     112         [ +  - ]:         28 :         if (repourl == NULL) {
     113                 :          0 :                 pkg_emit_error("%s: parse error", repo->url);
     114                 :          0 :                 fetchFreeURL(u);
     115                 :          0 :                 return (EPKG_FATAL);
     116                 :            :         }
     117                 :         28 :         retry = max_retry;
     118                 :         28 :         doc = u->doc;
     119                 :         28 :         reldoc = doc + strlen(repourl->doc);
     120                 :         28 :         fetchFreeURL(repourl);
     121                 :         28 :         pkg_debug(1, "Fetch > libfetch: connecting");
     122                 :            : 
     123         [ +  + ]:         44 :         while (repo->fh == NULL) {
     124   [ +  -  +  +  :         28 :                 if (repo != NULL && repo->mirror_type == SRV &&
                   #  # ]
     125                 :          4 :                     (strncmp(u->scheme, "http", 4) == 0
     126         [ -  + ]:          4 :                      || strcmp(u->scheme, "ftp") == 0)) {
     127         [ -  + ]:          4 :                         if (repo->srv == NULL) {
     128                 :          8 :                                 snprintf(zone, sizeof(zone),
     129                 :          4 :                                     "_%s._tcp.%s", u->scheme, u->host);
     130                 :          4 :                                 repo->srv = dns_getsrvinfo(zone);
     131                 :          4 :                         }
     132                 :            : 
     133                 :          4 :                         srv_current = repo->srv;
     134   [ +  -  -  +  :         28 :                         } else if (repo != NULL && repo->mirror_type == HTTP &&
                   #  # ]
     135                 :          0 :                             strncmp(u->scheme, "http", 4) == 0) {
     136         [ #  # ]:          0 :                                 if (u->port == 0) {
     137         [ #  # ]:          0 :                                         if (strcmp(u->scheme, "https") == 0)
     138                 :          0 :                                                 u->port = 443;
     139                 :            :                                         else
     140                 :          0 :                                                 u->port = 80;
     141                 :          0 :                                 }
     142                 :          0 :                                 snprintf(zone, sizeof(zone),
     143                 :          0 :                                     "%s://%s:%d", u->scheme, u->host, u->port);
     144         [ #  # ]:          0 :                                 if (repo->http == NULL)
     145                 :          0 :                                         gethttpmirrors(repo, zone, false);
     146         [ #  # ]:          0 :                                 if (repo->http == NULL)
     147                 :          0 :                                         gethttpmirrors(repo, repo->url, true);
     148                 :            : 
     149                 :          0 :                                 http_current = repo->http;
     150                 :          0 :                         }
     151   [ +  -  +  +  :         28 :                 if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
                   +  - ]
     152                 :          0 :                         strlcpy(u->host, srv_current->host, sizeof(u->host));
     153                 :          0 :                         u->port = srv_current->port;
     154   [ +  -  -  +  :         28 :                 } else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
                   #  # ]
     155                 :          0 :                         strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme));
     156                 :          0 :                         strlcpy(u->host, http_current->url->host, sizeof(u->host));
     157                 :          0 :                         snprintf(docpath, sizeof(docpath), "%s%s",
     158         [ #  # ]:          0 :                             http_current->url->doc, http_current->reldoc ? reldoc : doc);
     159                 :          0 :                         u->doc = docpath;
     160                 :          0 :                         u->port = http_current->url->port;
     161                 :          0 :                 }
     162                 :         28 :                 fetchOpts = xstring_new();
     163                 :         28 :                 fputs("i", fetchOpts->fp);
     164         [ -  + ]:         28 :                 if (repo != NULL) {
     165         [ -  + ]:         28 :                         if ((repo->flags & REPO_FLAGS_USE_IPV4) ==
     166                 :            :                             REPO_FLAGS_USE_IPV4)
     167                 :          0 :                                 fputs("4", fetchOpts->fp);
     168         [ +  - ]:         28 :                         else if ((repo->flags & REPO_FLAGS_USE_IPV6) ==
     169                 :            :                             REPO_FLAGS_USE_IPV6)
     170                 :          0 :                                 fputs("6", fetchOpts->fp);
     171                 :         28 :                 }
     172                 :            : 
     173         [ +  - ]:         28 :                 if (ctx.debug_level >= 4)
     174                 :          0 :                         fputs("v", fetchOpts->fp);
     175                 :            : 
     176                 :         28 :                 opts = xstring_get(fetchOpts);
     177                 :         28 :                 pkg_debug(1,"Fetch: fetching from: %s://%s%s%s%s with opts \"%s\"",
     178                 :         28 :                     u->scheme,
     179                 :         28 :                     u->user,
     180                 :         28 :                     u->user[0] != '\0' ? "@" : "",
     181                 :         28 :                     u->host,
     182                 :         28 :                     u->doc,
     183                 :         28 :                     opts);
     184                 :            : 
     185                 :         28 :                 repo->fh = fetchXGet(u, &st, opts);
     186                 :         28 :                 u->ims_time = st.mtime;
     187         [ +  + ]:         28 :                 if (repo->fh == NULL) {
     188         [ -  + ]:         12 :                         if (fetchLastErrCode == FETCH_OK) {
     189                 :         12 :                                 retcode = EPKG_UPTODATE;
     190                 :         12 :                                 goto cleanup;
     191                 :            :                         }
     192                 :          0 :                         --retry;
     193   [ #  #  #  # ]:          0 :                         if (retry <= 0 || fetchLastErrCode == FETCH_UNAVAIL) {
     194         [ #  # ]:          0 :                                  if (!repo->silent)
     195                 :          0 :                                         pkg_emit_error("%s://%s%s%s%s: %s",
     196                 :          0 :                                             u->scheme,
     197                 :          0 :                                             u->user,
     198                 :          0 :                                             u->user[0] != '\0' ? "@" : "",
     199                 :          0 :                                             u->host,
     200                 :          0 :                                             u->doc,
     201                 :            :                                             fetchLastErrString);
     202                 :          0 :                                 retcode = EPKG_FATAL;
     203                 :          0 :                                 goto cleanup;
     204                 :            :                         }
     205   [ #  #  #  #  :          0 :                         if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
                   #  # ]
     206                 :          0 :                                 srv_current = srv_current->next;
     207         [ #  # ]:          0 :                                 if (srv_current == NULL)
     208                 :          0 :                                         srv_current = repo->srv;
     209   [ #  #  #  #  :          0 :                         } else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
                   #  # ]
     210                 :          0 :                                 http_current = repo->http->next;
     211         [ #  # ]:          0 :                                 if (http_current == NULL)
     212                 :          0 :                                         http_current = repo->http;
     213                 :          0 :                         } else {
     214                 :          0 :                                 sleep(1);
     215                 :            :                         }
     216                 :          0 :                 }
     217                 :            :         }
     218                 :            : cleanup:
     219                 :         28 :         u->doc = doc;
     220   [ +  +  +  - ]:         28 :         if (retcode != EPKG_OK && repo->fh != NULL) {
     221                 :          0 :                 fclose(repo->fh);
     222                 :          0 :                 repo->fh = NULL;
     223                 :          0 :         }
     224                 :         28 :         return (retcode);
     225                 :         28 : }
     226                 :            : 
     227                 :            : int
     228                 :         28 : fetch_open(struct pkg_repo *repo, struct url *u, off_t *sz)
     229                 :            : {
     230                 :         28 :         int retcode = EPKG_FATAL;
     231                 :            : 
     232                 :         28 :         pkg_debug(1, "opening libfetch fetcher");
     233         [ +  - ]:         28 :         if (repo->fh == NULL)
     234                 :         28 :                 retcode = fetch_connect(repo, u);
     235                 :            : 
     236         [ +  + ]:         28 :         if (retcode == EPKG_OK)
     237                 :         16 :                 *sz = u->length;
     238                 :            : 
     239                 :         28 :         return (retcode);
     240                 :            : }

Generated by: LCOV version 1.15