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 : : }
|