1 /* librepo - A library providing (libcURL like) API to downloading repository
2 * Copyright (C) 2012 Tomas Mlcoch
3 *
4 * Licensed under the GNU Lesser General Public License Version 2.1
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #define _POSIX_C_SOURCE 200809L
22 #define _BSD_SOURCE
23
24 #include <glib.h>
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <assert.h>
29 #include <stdarg.h>
30 #include <curl/curl.h>
31 #include <sys/types.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35
36
37 #include "handle_internal.h"
38 #include "handle.h"
39 #include "result_internal.h"
40 #include "repomd.h"
41 #include "rcodes.h"
42 #include "util.h"
43 #include "yum.h"
44 #include "version.h"
45 #include "yum_internal.h"
46 #include "url_substitution.h"
47 #include "downloader.h"
48 #include "fastestmirror_internal.h"
49 #include "cleanup.h"
50
51 CURL *
lr_get_curl_handle()52 lr_get_curl_handle()
53 {
54 CURL *h;
55
56 lr_global_init();
57
58 h = curl_easy_init();
59 if (!h)
60 return NULL;
61
62 if (curl_easy_setopt(h, CURLOPT_FOLLOWLOCATION, 1) != CURLE_OK)
63 goto err;
64 if (curl_easy_setopt(h, CURLOPT_MAXREDIRS, 6) != CURLE_OK)
65 goto err;
66 if (curl_easy_setopt(h, CURLOPT_CONNECTTIMEOUT, LRO_CONNECTTIMEOUT_DEFAULT) != CURLE_OK)
67 goto err;
68 if (curl_easy_setopt(h, CURLOPT_LOW_SPEED_TIME, LRO_LOWSPEEDTIME_DEFAULT) != CURLE_OK)
69 goto err;
70 if (curl_easy_setopt(h, CURLOPT_LOW_SPEED_LIMIT, LRO_LOWSPEEDLIMIT_DEFAULT) != CURLE_OK)
71 goto err;
72 if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYHOST, 2) != CURLE_OK)
73 goto err;
74 if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYPEER, 1) != CURLE_OK)
75 goto err;
76 if (curl_easy_setopt(h, CURLOPT_SSL_VERIFYSTATUS, 0) != CURLE_OK)
77 goto err;
78 if (curl_easy_setopt(h, CURLOPT_FTP_USE_EPSV, LRO_FTPUSEEPSV_DEFAULT) != CURLE_OK)
79 goto err;
80 if (curl_easy_setopt(h, CURLOPT_FILETIME, 0) != CURLE_OK)
81 goto err;
82
83 return h;
84
85 err:
86 curl_easy_cleanup(h);
87 return NULL;
88 }
89
90 void
lr_handle_free_list(char *** list)91 lr_handle_free_list(char ***list)
92 {
93 if (!list || *list == NULL)
94 return;
95 for (int x=0; (*list)[x]; x++)
96 lr_free((*list)[x]);
97 lr_free(*list);
98 *list = NULL;
99 }
100
101 LrHandle *
lr_handle_init(void)102 lr_handle_init(void)
103 {
104 LrHandle *handle;
105 CURL *curl = lr_get_curl_handle();
106
107 if (!curl)
108 return NULL;
109
110 handle = lr_malloc0(sizeof(LrHandle));
111 handle->curl_handle = curl;
112 handle->fastestmirrormaxage = LRO_FASTESTMIRRORMAXAGE_DEFAULT;
113 handle->mirrorlist_fd = -1;
114 handle->metalink_fd = -1;
115 handle->onetimeflag_apply = FALSE;
116 handle->checks |= LR_CHECK_CHECKSUM;
117 handle->maxparalleldownloads = LRO_MAXPARALLELDOWNLOADS_DEFAULT;
118 handle->maxdownloadspermirror = LRO_MAXDOWNLOADSPERMIRROR_DEFAULT;
119 handle->lowspeedtime = LRO_LOWSPEEDTIME_DEFAULT;
120 handle->lowspeedlimit = LRO_LOWSPEEDLIMIT_DEFAULT;
121 handle->sslverifypeer = 1;
122 handle->sslverifyhost = 2;
123 handle->sslverifystatus = 0;
124 handle->proxy_sslverifypeer = 1;
125 handle->proxy_sslverifyhost = 2;
126 handle->ipresolve = LRO_IPRESOLVE_DEFAULT;
127 handle->allowed_mirror_failures = LRO_ALLOWEDMIRRORFAILURES_DEFAULT;
128 handle->adaptivemirrorsorting = LRO_ADAPTIVEMIRRORSORTING_DEFAULT;
129 handle->gnupghomedir = g_strdup(LRO_GNUPGHOMEDIR_DEFAULT);
130 handle->fastestmirrortimeout = LRO_FASTESTMIRRORTIMEOUT_DEFAULT;
131 handle->offline = LRO_OFFLINE_DEFAULT;
132 handle->httpauthmethods = LRO_HTTPAUTHMETHODS_DEFAULT;
133 handle->proxyauthmethods = LRO_PROXYAUTHMETHODS_DEFAULT;
134 handle->ftpuseepsv = LRO_FTPUSEEPSV_DEFAULT;
135 handle->cachedir = NULL;
136 handle->preservetime = 0;
137
138 return handle;
139 }
140
141 void
lr_handle_free(LrHandle * handle)142 lr_handle_free(LrHandle *handle)
143 {
144 if (!handle)
145 return;
146 if (handle->curl_handle)
147 curl_easy_cleanup(handle->curl_handle);
148 if (handle->mirrorlist_fd != -1)
149 close(handle->mirrorlist_fd);
150 if (handle->metalink_fd != -1)
151 close(handle->metalink_fd);
152 lr_handle_free_list(&handle->urls);
153 lr_free(handle->fastestmirrorcache);
154 lr_free(handle->mirrorlist);
155 lr_free(handle->mirrorlisturl);
156 lr_free(handle->metalinkurl);
157 lr_free(handle->onetimeflag);
158 lr_free(handle->used_mirror);
159 lr_free(handle->destdir);
160 lr_free(handle->useragent);
161 lr_free(handle->sslclientcert);
162 lr_free(handle->sslclientkey);
163 lr_free(handle->sslcacert);
164 lr_free(handle->proxy_sslclientcert);
165 lr_free(handle->proxy_sslclientkey);
166 lr_free(handle->proxy_sslcacert);
167 lr_lrmirrorlist_free(handle->internal_mirrorlist);
168 lr_lrmirrorlist_free(handle->urls_mirrors);
169 lr_lrmirrorlist_free(handle->mirrorlist_mirrors);
170 lr_lrmirrorlist_free(handle->metalink_mirrors);
171 lr_lrmirrorlist_free(handle->mirrors);
172 lr_metalink_free(handle->metalink);
173 lr_handle_free_list(&handle->yumdlist);
174 lr_urlvars_free(handle->yumslist);
175 lr_handle_free_list(&handle->yumblist);
176 lr_urlvars_free(handle->urlvars);
177 lr_free(handle->gnupghomedir);
178 lr_free(handle->cachedir);
179 lr_handle_free_list(&handle->httpheader);
180 lr_free(handle);
181 }
182
183 typedef enum {
184 LR_REMOTESOURCE_URLS,
185 LR_REMOTESOURCE_MIRRORLIST,
186 LR_REMOTESOURCE_METALINK,
187 LR_REMOTESOURCE_LOCAL_OPT,
188 LR_REMOTESOURCE_OFFLINE_OPT,
189 LR_REMOTESOURCE_OTHER,
190 } LrChangedRemoteSource;
191
curlauth_bitmask(LrAuth mask)192 static unsigned long curlauth_bitmask(LrAuth mask)
193 {
194 unsigned long out_mask = 0UL;
195
196 if (mask == LR_AUTH_NONE)
197 return (unsigned long) CURLAUTH_NONE;
198
199 if (mask & LR_AUTH_BASIC)
200 out_mask |= CURLAUTH_BASIC;
201 if (mask & LR_AUTH_DIGEST)
202 out_mask |= CURLAUTH_DIGEST;
203 if (mask & LR_AUTH_NEGOTIATE)
204 #ifdef CURLAUTH_NEGOTIATE
205 out_mask |= CURLAUTH_NEGOTIATE;
206 #else
207 out_mask |= CURLAUTH_GSSNEGOTIATE;
208 #endif
209 if (mask & LR_AUTH_NTLM)
210 out_mask |= CURLAUTH_NTLM;
211 if (mask & LR_AUTH_DIGEST_IE)
212 out_mask |= CURLAUTH_DIGEST_IE;
213 if (mask & LR_AUTH_NTLM_WB)
214 out_mask |= CURLAUTH_NTLM_WB;
215 if (mask & LR_AUTH_ONLY)
216 out_mask |= CURLAUTH_ONLY;
217 if (mask == LR_AUTH_ANY)
218 out_mask |= CURLAUTH_ANY;
219
220 return out_mask;
221 }
222
223 static void
lr_handle_remote_sources_changed(LrHandle * handle,LrChangedRemoteSource type)224 lr_handle_remote_sources_changed(LrHandle *handle, LrChangedRemoteSource type)
225 {
226 // Called when options like:
227 // LRO_URLS
228 // LRO_MIRRORLIST
229 // LRO_MIRRORLISTURL
230 // LRO_METALINKURL
231 // LRO_LOCAL
232 // LRO_OFFLINE
233 // are changed
234
235 // Internal mirrorlist is no more valid
236 lr_lrmirrorlist_free(handle->internal_mirrorlist);
237 handle->internal_mirrorlist = NULL;
238
239 // Mirrors reported via mirrors are no more valid too
240 lr_lrmirrorlist_free(handle->mirrors);
241 handle->mirrors = NULL;
242
243 if (type == LR_REMOTESOURCE_URLS) {
244 lr_lrmirrorlist_free(handle->urls_mirrors);
245 handle->urls_mirrors = NULL;
246 }
247
248 if (type == LR_REMOTESOURCE_MIRRORLIST) {
249 lr_lrmirrorlist_free(handle->mirrorlist_mirrors);
250 handle->mirrorlist_mirrors = NULL;
251 if (handle->mirrorlist_fd != -1)
252 close(handle->mirrorlist_fd);
253 handle->mirrorlist_fd = -1;
254 }
255
256 if (type == LR_REMOTESOURCE_METALINK) {
257 lr_lrmirrorlist_free(handle->metalink_mirrors);
258 handle->metalink_mirrors = NULL;
259 if (handle->metalink_fd != -1)
260 close(handle->metalink_fd);
261 handle->metalink_fd = -1;
262 lr_metalink_free(handle->metalink);
263 handle->metalink = NULL;
264 }
265 }
266
267 gboolean
lr_handle_setopt(LrHandle * handle,GError ** err,LrHandleOption option,...)268 lr_handle_setopt(LrHandle *handle,
269 GError **err,
270 LrHandleOption option,
271 ...)
272 {
273 gboolean ret = TRUE;
274 va_list arg;
275 CURLcode c_rc = CURLE_OK;
276 CURL *c_h;
277
278 assert(!err || *err == NULL);
279
280 // Variables for values from va_arg
281 long val_long;
282 gint64 val_gint64;
283
284 if (!handle) {
285 g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
286 "No handle specified");
287 return FALSE;
288 }
289
290 c_h = handle->curl_handle;
291
292 va_start(arg, option);
293
294 switch (option) {
295 case LRO_UPDATE:
296 handle->update = va_arg(arg, long) ? 1 : 0;
297 break;
298
299 case LRO_MIRRORLIST:
300 // DEPRECATED!
301 g_warning("WARNING! Deprecated LRO_MIRRORLIST used");
302 if (handle->mirrorlist) lr_free(handle->mirrorlist);
303 handle->mirrorlist = g_strdup(va_arg(arg, char *));
304
305 if (handle->mirrorlisturl)
306 lr_free(handle->mirrorlisturl);
307 handle->mirrorlisturl = NULL;
308 if (handle->metalinkurl)
309 lr_free(handle->metalinkurl);
310 handle->metalinkurl = NULL;
311 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_MIRRORLIST);
312 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_METALINK);
313
314 if (!handle->mirrorlist)
315 break;
316
317 if (strstr(handle->mirrorlist, "metalink"))
318 handle->metalinkurl = g_strdup(handle->mirrorlist);
319 else
320 handle->mirrorlisturl = g_strdup(handle->mirrorlist);
321 break;
322
323 case LRO_MIRRORLISTURL:
324 if (handle->mirrorlisturl)
325 lr_free(handle->mirrorlisturl);
326 handle->mirrorlisturl = g_strdup(va_arg(arg, char *));
327 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_MIRRORLIST);
328 break;
329
330 case LRO_METALINKURL:
331 if (handle->metalinkurl)
332 lr_free(handle->metalinkurl);
333 handle->metalinkurl = g_strdup(va_arg(arg, char *));
334 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_METALINK);
335 break;
336
337 case LRO_ONETIMEFLAG:
338 if (handle->onetimeflag)
339 lr_free(handle->onetimeflag);
340 handle->onetimeflag = g_strdup(va_arg(arg, char *));
341 break;
342
343 case LRO_LOCAL:
344 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_LOCAL_OPT);
345 handle->local = va_arg(arg, long) ? 1 : 0;
346 break;
347
348 case LRO_HTTPAUTH:
349 if (va_arg(arg, long) == 0) {
350 c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
351 handle->httpauthmethods = LR_AUTH_BASIC;
352 } else {
353 c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
354 handle->httpauthmethods = LR_AUTH_ANY;
355 }
356 break;
357
358 case LRO_USERPWD:
359 c_rc = curl_easy_setopt(c_h, CURLOPT_USERPWD, va_arg(arg, char *));
360 break;
361
362 case LRO_PROXY:
363 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY, va_arg(arg, char *));
364 break;
365
366 case LRO_PROXYPORT: {
367 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYPORT,va_arg(arg, long));
368 break;
369 }
370
371 case LRO_PROXYTYPE: {
372 long curl_proxy = -1;
373 switch (va_arg(arg, long)) {
374 case LR_PROXY_HTTP: curl_proxy = CURLPROXY_HTTP; break;
375 case LR_PROXY_HTTP_1_0: curl_proxy = CURLPROXY_HTTP_1_0;break;
376 case LR_PROXY_SOCKS4: curl_proxy = CURLPROXY_SOCKS4; break;
377 case LR_PROXY_SOCKS5: curl_proxy = CURLPROXY_SOCKS5; break;
378 case LR_PROXY_SOCKS4A: curl_proxy = CURLPROXY_SOCKS4A; break;
379 case LR_PROXY_SOCKS5_HOSTNAME: curl_proxy = CURLPROXY_SOCKS5_HOSTNAME; break;
380 default: break;
381 }
382 if (curl_proxy == -1) {
383 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
384 "Bad LRO_PROXYTYPE value");
385 ret = FALSE;
386 } else {
387 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYTYPE, curl_proxy);
388 }
389 break;
390 }
391
392 case LRO_PROXYAUTH:
393 if (va_arg(arg, long) == 0) {
394 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
395 handle->proxyauthmethods = LR_AUTH_BASIC;
396 } else {
397 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
398 handle->proxyauthmethods = LR_AUTH_ANY;
399 }
400 break;
401
402 case LRO_PROXYUSERPWD:
403 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYUSERPWD, va_arg(arg, char *));
404 break;
405
406 case LRO_PROGRESSCB:
407 handle->user_cb = va_arg(arg, LrProgressCb);
408 break;
409
410 case LRO_PROGRESSDATA:
411 handle->user_data = va_arg(arg, void *);
412 break;
413
414 case LRO_MAXSPEED:
415 val_gint64 = va_arg(arg, gint64);
416 if (val_gint64 < 0) {
417 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
418 "Bad value of LRO_MAXSPEED");
419 ret = FALSE;
420 break;
421 } else if (val_gint64 != 0 && val_gint64 < handle->lowspeedlimit) {
422 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
423 "LRO_MAXSPEED (%"G_GINT64_FORMAT") is lower than "
424 "LRO_LOWSPEEDLIMIT (%ld)", val_gint64,
425 handle->lowspeedlimit);
426 ret = FALSE;
427 break;
428 }
429 handle->maxspeed = val_gint64;
430 break;
431
432 case LRO_DESTDIR:
433 if (handle->destdir) lr_free(handle->destdir);
434 handle->destdir = g_strdup(va_arg(arg, char *));
435 break;
436
437 case LRO_REPOTYPE:
438 handle->repotype = va_arg(arg, LrRepotype);
439 if (handle->repotype != LR_YUMREPO) {
440 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
441 "Bad value of LRO_REPOTYPE");
442 ret = FALSE;
443 }
444 break;
445
446 case LRO_CONNECTTIMEOUT:
447 c_rc = curl_easy_setopt(c_h, CURLOPT_CONNECTTIMEOUT, va_arg(arg, long));
448 break;
449
450 case LRO_IGNOREMISSING:
451 handle->ignoremissing = va_arg(arg, long) ? 1 : 0;
452 break;
453
454 case LRO_INTERRUPTIBLE:
455 handle->interruptible = va_arg(arg, long) ? 1 : 0;
456 break;
457
458 case LRO_USERAGENT: {
459 char *useragent = va_arg(arg, char *);
460 if (handle->useragent) lr_free(handle->useragent);
461 handle->useragent = g_strdup(useragent);
462 c_rc = curl_easy_setopt(c_h, CURLOPT_USERAGENT, useragent);
463 break;
464 }
465
466 case LRO_GPGCHECK:
467 if (va_arg(arg, long))
468 handle->checks |= LR_CHECK_GPG;
469 else
470 handle->checks &= ~LR_CHECK_GPG;
471 break;
472
473 case LRO_CHECKSUM:
474 if (va_arg(arg, long))
475 handle->checks |= LR_CHECK_CHECKSUM;
476 else
477 handle->checks &= ~LR_CHECK_CHECKSUM;
478 break;
479
480 case LRO_URLS:
481 case LRO_YUMDLIST:
482 case LRO_YUMBLIST:
483 {
484 int size = 0;
485 char **list = va_arg(arg, char **);
486 char ***handle_list = NULL;
487
488 if (option == LRO_URLS) {
489 handle_list = &handle->urls;
490 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_URLS);
491 } else if (option == LRO_YUMDLIST) {
492 handle_list = &handle->yumdlist;
493 } else if (option == LRO_YUMBLIST) {
494 handle_list = &handle->yumblist;
495 }
496
497 lr_handle_free_list(handle_list);
498 if (!list)
499 break;
500
501 // Get list length
502 while (list[size])
503 size++;
504 size++;
505
506 if (size == 1 && option == LRO_URLS) {
507 // Only NULL present in list of URLs, keep handle->urls = NULL
508 break;
509 }
510
511 // Copy the list
512 *handle_list = lr_strv_dup(list);
513 break;
514 }
515
516 case LRO_HTTPHEADER:
517 {
518 char **list = va_arg(arg, char **);
519 lr_handle_free_list(&handle->httpheader);
520 handle->httpheader = lr_strv_dup(list);
521 break;
522 }
523
524 case LRO_FETCHMIRRORS:
525 handle->fetchmirrors = va_arg(arg, long) ? 1 : 0;
526 break;
527
528 case LRO_MAXMIRRORTRIES:
529 val_long = va_arg(arg, long);
530
531 if (handle->maxmirrortries < LRO_MAXMIRRORTRIES_MIN) {
532 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
533 "Value of LRO_MAXMIRRORTRIES is too low (use value > %ld)",
534 LRO_MAXMIRRORTRIES_MIN);
535 ret = FALSE;
536 } else {
537 handle->maxmirrortries = val_long;
538 }
539
540 break;
541
542 case LRO_MAXPARALLELDOWNLOADS:
543 val_long = va_arg(arg, long);
544
545 if (val_long < LRO_MAXPARALLELDOWNLOADS_MIN ||
546 val_long > LRO_MAXPARALLELDOWNLOADS_MAX) {
547 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
548 "Bad value of LRO_MAXPARALLELDOWNLOADS.");
549 ret = FALSE;
550 } else {
551 handle->maxparalleldownloads = val_long;
552 }
553
554 break;
555
556 case LRO_MAXDOWNLOADSPERMIRROR:
557 val_long = va_arg(arg, long);
558
559 if (val_long < LRO_MAXDOWNLOADSPERMIRROR_MIN) {
560 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
561 "Value of LRO_MAXDOWNLOADSPERMIRROR is too low.");
562 ret = FALSE;
563 } else {
564 handle->maxdownloadspermirror = val_long;
565 }
566
567 break;
568
569 case LRO_YUMSLIST: {
570 LrUrlVars *vars = va_arg(arg, LrUrlVars *);
571 lr_urlvars_free(handle->yumslist);
572 handle->yumslist = vars;
573 break;
574 }
575
576 case LRO_VARSUB: {
577 LrUrlVars *vars = va_arg(arg, LrUrlVars *);
578 lr_urlvars_free(handle->urlvars);
579 handle->urlvars = vars;
580
581 /* Do not do copy
582 for (LrUrlVars *elem = vars; elem; elem = lr_list_next(elem)) {
583 LrVar *var = elem->data;
584 handle->urlvars = lr_urlvars_set(handle->urlvars, var->var, var->val);
585 }
586 */
587
588 break;
589 }
590
591 case LRO_FASTESTMIRROR:
592 handle->fastestmirror = va_arg(arg, long) ? 1 : 0;
593 break;
594
595 case LRO_FASTESTMIRRORCACHE: {
596 char *fastestmirrorcache = va_arg(arg, char *);
597 if (handle->fastestmirrorcache) lr_free(handle->fastestmirrorcache);
598 handle->fastestmirrorcache = g_strdup(fastestmirrorcache);
599 break;
600 }
601
602 case LRO_FASTESTMIRRORMAXAGE:
603 val_long = va_arg(arg, long);
604
605 if (val_long < LRO_FASTESTMIRRORMAXAGE_MIN) {
606 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
607 "Value of LRO_FASTESTMIRRORMAXAGE is too low.");
608 ret = FALSE;
609 } else {
610 handle->fastestmirrormaxage = val_long;
611 }
612
613 break;
614
615 case LRO_FASTESTMIRRORCB:
616 handle->fastestmirrorcb = va_arg(arg, LrFastestMirrorCb);
617 break;
618
619 case LRO_FASTESTMIRRORDATA:
620 handle->fastestmirrordata = va_arg(arg, void *);
621 break;
622
623 case LRO_LOWSPEEDTIME:
624 val_long = va_arg(arg, long);
625
626 if (val_long < LRO_LOWSPEEDTIME_MIN) {
627 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
628 "Value of LRO_LOWSPEEDTIME is too low.");
629 ret = FALSE;
630 } else {
631 c_rc = curl_easy_setopt(c_h, CURLOPT_LOW_SPEED_TIME, val_long);
632 handle->lowspeedtime = val_long;
633 }
634
635 break;
636
637 case LRO_LOWSPEEDLIMIT:
638 val_long = va_arg(arg, long);
639
640 if (val_long < LRO_LOWSPEEDLIMIT_MIN) {
641 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
642 "Value of LRO_LOWSPEEDLIMIT is too low.");
643 ret = FALSE;
644 } else if (handle->maxspeed != 0 && handle->maxspeed < val_long) {
645 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
646 "Value of LRO_LOWSPEEDLIMIT (%ld) is higher than "
647 "LRO_MAXSPEED (%"G_GINT64_FORMAT")",
648 val_long, handle->maxspeed);
649 ret = FALSE;
650 } else {
651 c_rc = curl_easy_setopt(c_h, CURLOPT_LOW_SPEED_LIMIT, val_long);
652 handle->lowspeedlimit = val_long;
653 }
654
655 break;
656
657 case LRO_HMFCB:
658 handle->hmfcb = va_arg(arg, LrHandleMirrorFailureCb);
659 break;
660
661 case LRO_SSLVERIFYPEER:
662 handle->sslverifypeer = va_arg(arg, long) ? 1 : 0;
663 c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYPEER, handle->sslverifypeer);
664 break;
665
666 case LRO_SSLVERIFYSTATUS:
667 handle->sslverifystatus = va_arg(arg, long) ? 1 : 0;
668 c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYSTATUS, handle->sslverifystatus);
669 break;
670
671 case LRO_SSLVERIFYHOST:
672 handle->sslverifyhost = va_arg(arg, long) ? 2 : 0;
673 c_rc = curl_easy_setopt(c_h, CURLOPT_SSL_VERIFYHOST, handle->sslverifyhost);
674 break;
675
676 case LRO_SSLCLIENTCERT:
677 if (handle->sslclientcert)
678 lr_free(handle->sslclientcert);
679 handle->sslclientcert = g_strdup(va_arg(arg, char *));
680 c_rc = curl_easy_setopt(c_h, CURLOPT_SSLCERT, handle->sslclientcert);
681 if (c_rc == CURLE_OK && handle->sslclientcert && !strncasecmp(handle->sslclientcert, "pkcs11:", 7)) {
682 c_rc = curl_easy_setopt(c_h, CURLOPT_SSLCERTTYPE, "ENG");
683 }
684 break;
685
686 case LRO_SSLCLIENTKEY:
687 if (handle->sslclientkey)
688 lr_free(handle->sslclientkey);
689 handle->sslclientkey = g_strdup(va_arg(arg, char *));
690 c_rc = curl_easy_setopt(c_h, CURLOPT_SSLKEY, handle->sslclientkey);
691 if (c_rc == CURLE_OK && handle->sslclientkey && !strncasecmp(handle->sslclientkey, "pkcs11:", 7)) {
692 c_rc = curl_easy_setopt(c_h, CURLOPT_SSLKEYTYPE, "ENG");
693 }
694 break;
695
696 case LRO_SSLCACERT:
697 if (handle->sslcacert)
698 lr_free(handle->sslcacert);
699 handle->sslcacert = g_strdup(va_arg(arg, char *));
700 c_rc = curl_easy_setopt(c_h, CURLOPT_CAINFO, handle->sslcacert);
701 break;
702
703 case LRO_PROXY_SSLVERIFYPEER:
704 handle->proxy_sslverifypeer = va_arg(arg, long) ? 1 : 0;
705 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSL_VERIFYPEER, handle->proxy_sslverifypeer);
706 break;
707
708 case LRO_PROXY_SSLVERIFYHOST:
709 handle->proxy_sslverifyhost = va_arg(arg, long) ? 2 : 0;
710 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSL_VERIFYHOST, handle->proxy_sslverifyhost);
711 break;
712
713 case LRO_PROXY_SSLCLIENTCERT:
714 if (handle->proxy_sslclientcert)
715 lr_free(handle->proxy_sslclientcert);
716 handle->proxy_sslclientcert = g_strdup(va_arg(arg, char *));
717 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLCERT, handle->proxy_sslclientcert);
718 if (c_rc == CURLE_OK && handle->proxy_sslclientcert && !strncasecmp(handle->proxy_sslclientcert, "pkcs11:", 7)) {
719 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLCERTTYPE, "ENG");
720 }
721 break;
722
723 case LRO_PROXY_SSLCLIENTKEY:
724 if (handle->proxy_sslclientkey)
725 lr_free(handle->proxy_sslclientkey);
726 handle->proxy_sslclientkey = g_strdup(va_arg(arg, char *));
727 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLKEY, handle->proxy_sslclientkey);
728 if (c_rc == CURLE_OK && handle->proxy_sslclientkey && !strncasecmp(handle->proxy_sslclientkey, "pkcs11:", 7)) {
729 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_SSLKEYTYPE, "ENG");
730 }
731 break;
732
733 case LRO_PROXY_SSLCACERT:
734 if (handle->proxy_sslcacert)
735 lr_free(handle->proxy_sslcacert);
736 handle->proxy_sslcacert = g_strdup(va_arg(arg, char *));
737 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXY_CAINFO, handle->proxy_sslcacert);
738 break;
739
740 case LRO_IPRESOLVE: {
741 long type = -1;
742 long lr_type = va_arg(arg, LrIpResolveType);
743 switch (lr_type) {
744 case LR_IPRESOLVE_WHATEVER: type = CURL_IPRESOLVE_WHATEVER; break;
745 case LR_IPRESOLVE_V4: type = CURL_IPRESOLVE_V4; break;
746 case LR_IPRESOLVE_V6: type = CURL_IPRESOLVE_V6; break;
747 default: break;
748 }
749 if (type == -1) {
750 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
751 "Bad LRO_IPRESOLVE value");
752 ret = FALSE;
753 } else {
754 handle->ipresolve = lr_type;
755 c_rc = curl_easy_setopt(c_h, CURLOPT_IPRESOLVE, type);
756 }
757 break;
758 }
759
760 case LRO_ALLOWEDMIRRORFAILURES:
761 handle->allowed_mirror_failures = va_arg(arg, long);
762 break;
763
764 case LRO_ADAPTIVEMIRRORSORTING:
765 handle->adaptivemirrorsorting = va_arg(arg, long);
766 break;
767
768 case LRO_GNUPGHOMEDIR: {
769 char *gnupghomedir = va_arg(arg, char *);
770 lr_free(handle->gnupghomedir);
771 handle->gnupghomedir = g_strdup(gnupghomedir);
772 break;
773 }
774
775 case LRO_FASTESTMIRRORTIMEOUT:
776 handle->fastestmirrortimeout = va_arg(arg, double);
777 break;
778
779 case LRO_OFFLINE:
780 lr_handle_remote_sources_changed(handle, LR_REMOTESOURCE_OFFLINE_OPT);
781 handle->offline = va_arg(arg, long) ? 1 : 0;
782 break;
783
784 case LRO_HTTPAUTHMETHODS: {
785 LrAuth in_bitmask = va_arg(arg, LrAuth);
786 long bitmask = curlauth_bitmask(in_bitmask);
787 handle->httpauthmethods = in_bitmask;
788 c_rc = curl_easy_setopt(c_h, CURLOPT_HTTPAUTH, bitmask);
789 break;
790 }
791
792 case LRO_PROXYAUTHMETHODS: {
793 LrAuth in_bitmask = va_arg(arg, LrAuth);
794 long bitmask = curlauth_bitmask(in_bitmask);
795 handle->proxyauthmethods = in_bitmask;
796 c_rc = curl_easy_setopt(c_h, CURLOPT_PROXYAUTH, bitmask);
797 break;
798 }
799
800 case LRO_FTPUSEEPSV:
801 handle->ftpuseepsv = va_arg(arg, long) ? 1 : 0;
802 c_rc = curl_easy_setopt(c_h, CURLOPT_FTP_USE_EPSV, handle->ftpuseepsv);
803 break;
804
805 case LRO_CACHEDIR:
806 if (handle->cachedir) lr_free(handle->cachedir);
807 handle->cachedir = g_strdup(va_arg(arg, char *));
808 break;
809
810 case LRO_PRESERVETIME:
811 handle->preservetime = va_arg(arg, long) ? 1 : 0;
812 c_rc = curl_easy_setopt(c_h, CURLOPT_FILETIME, handle->preservetime);
813 break;
814
815 default:
816 g_set_error(err, LR_HANDLE_ERROR, LRE_BADOPTARG,
817 "Unknown option");
818 ret = FALSE;
819 break;
820
821 };
822
823 /* Handle CURL error return code */
824 if (ret == TRUE && c_rc != CURLE_OK) {
825 ret = FALSE;
826 switch (c_rc) {
827 case CURLE_FAILED_INIT:
828 g_set_error(err, LR_HANDLE_ERROR, LRE_CURLSETOPT,
829 "curl_easy_setopt error: %s",
830 curl_easy_strerror(c_rc));
831 break;
832 default:
833 g_set_error(err, LR_HANDLE_ERROR, LRE_CURL,
834 "curl error: %s",
835 curl_easy_strerror(c_rc));
836 break;
837 };
838 }
839
840 va_end(arg);
841 return ret;
842 }
843
844 static gboolean
lr_handle_prepare_urls(LrHandle * handle,GError ** err)845 lr_handle_prepare_urls(LrHandle *handle, GError **err)
846 {
847 assert(!handle->urls_mirrors);
848
849 for (int x=0; handle->urls[x]; x++) {
850 gchar *url = handle->urls[x];
851 _cleanup_free_ gchar *final_url = NULL;
852
853 // Make sure that url has protocol specified
854 final_url = lr_prepend_url_protocol(url);
855 if (!final_url) {
856 g_set_error(err, LR_HANDLE_ERROR, LRE_BADURL,
857 "Cannot resolve path for: \"%s\"", url);
858 return FALSE;
859 }
860
861 // Append the url into internal list of urls specified by LRO_URLS
862 handle->urls_mirrors = lr_lrmirrorlist_append_url(
863 handle->urls_mirrors,
864 final_url,
865 handle->urlvars);
866 }
867
868 return TRUE;
869 }
870
871 static gboolean
lr_yum_download_url_retry(int attempts,LrHandle * lr_handle,const char * url,int fd,gboolean no_cache,gboolean is_zchunk,GError ** err)872 lr_yum_download_url_retry(int attempts, LrHandle *lr_handle, const char *url,
873 int fd, gboolean no_cache, gboolean is_zchunk,
874 GError **err)
875 {
876 gboolean ret = FALSE;
877
878 for (int i = 1;; i++) {
879 ret = lr_yum_download_url(lr_handle, url, fd, no_cache, is_zchunk, err);
880 if (ret)
881 return ret;
882
883 if (i >= attempts)
884 return ret; // Caller to handle the last err
885
886 g_debug("%s: Attempt #%d to download %s failed: %s",
887 __func__, i, url, (*err)->message);
888
889 if (ftruncate(fd, 0) < 0) {
890 g_set_error(err, LR_DOWNLOADER_ERROR, LRE_IO,
891 "ftruncate() failed: %s", g_strerror(errno));
892 return FALSE;
893 }
894
895 g_clear_error (err);
896 }
897 }
898
899 static gboolean
lr_handle_prepare_mirrorlist(LrHandle * handle,gchar * localpath,GError ** err)900 lr_handle_prepare_mirrorlist(LrHandle *handle, gchar *localpath, GError **err)
901 {
902 assert(handle->mirrorlist_fd == -1);
903 assert(!handle->mirrorlist_mirrors);
904
905 int fd = -1;
906
907 // Get file descriptor with content
908
909 if (!localpath && !handle->mirrorlisturl) {
910 // Nothing to do
911 return TRUE;
912 } else if (localpath && !handle->mirrorlisturl) {
913 // Just try to use mirrorlist of the local repository
914 _cleanup_free_ gchar *path = lr_pathconcat(localpath, "mirrorlist", NULL);
915
916 if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
917 g_debug("%s: Local mirrorlist found at %s", __func__, path);
918 fd = open(path, O_RDONLY);
919 if (fd < 0) {
920 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
921 "Cannot open %s: %s",
922 path, g_strerror(errno));
923 return FALSE;
924 }
925 } else {
926 // No local mirrorlist
927 return TRUE;
928 }
929 } else if (!handle->mirrorlisturl) {
930 // Nothing to do
931 return TRUE;
932 } else if (handle->offline && !lr_is_local_path(handle->mirrorlisturl)) {
933 // We should work offline, ignore remote mirrorlist
934 g_debug("%s: LRO_OFFLINE used, remote mirrorlist ignored: %s",
935 __func__, handle->mirrorlisturl);
936 return TRUE;
937 } else if (handle->local && !lr_is_local_path(handle->mirrorlisturl)) {
938 // We should work only locally, ignore remote mirrorlist
939 g_debug("%s: LRO_LOCAL used, remote mirrorlist ignored: %s",
940 __func__, handle->mirrorlisturl);
941 return TRUE;
942 } else if (handle->mirrorlisturl) {
943 // Download remote mirrorlist
944 _cleanup_free_ gchar *url = NULL;
945
946 fd = lr_gettmpfile();
947 if (fd < 0) {
948 g_debug("%s: Cannot create a temporary file", __func__);
949 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
950 "Cannot create a temporary file");
951 return FALSE;
952 }
953
954 url = lr_prepend_url_protocol(handle->mirrorlisturl);
955 handle->onetimeflag_apply = TRUE;
956 if (!lr_yum_download_url_retry(3, handle, url, fd, TRUE, FALSE, err)) {
957 close(fd);
958 return FALSE;
959 }
960
961 if (lseek(fd, 0, SEEK_SET) != 0) {
962 g_debug("%s: Seek error: %s", __func__, g_strerror(errno));
963 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
964 "lseek(%d, 0, SEEK_SET) error: %s",
965 fd, g_strerror(errno));
966 close(fd);
967 return FALSE;
968 }
969 }
970
971 assert(fd >= 0);
972
973 // Parse the file descriptor content
974
975 g_debug("%s: Parsing mirrorlist", __func__);
976
977 LrMirrorlist *ml = lr_mirrorlist_init();
978 gboolean ret = lr_mirrorlist_parse_file(ml, fd, err);
979 if (!ret) {
980 g_debug("%s: Error while parsing mirrorlist", __func__);
981 close(fd);
982 lr_mirrorlist_free(ml);
983 return FALSE;
984 }
985
986 if (!ml->urls) {
987 g_debug("%s: No URLs in mirrorlist", __func__);
988 g_set_error(err, LR_HANDLE_ERROR, LRE_MLBAD, "No URLs in mirrorlist");
989 close(fd);
990 lr_mirrorlist_free(ml);
991 return FALSE;
992 }
993
994 // List parsed mirrors
995 g_debug("%s: Mirrors from mirrorlist:", __func__);
996 for (GSList *elem = ml->urls; elem; elem = g_slist_next(elem))
997 g_debug(" %s", (gchar *) elem->data);
998
999 // Convert mirrorlist to internal mirrorlist format
1000
1001 handle->mirrorlist_mirrors = lr_lrmirrorlist_append_mirrorlist(
1002 NULL,
1003 ml,
1004 handle->urlvars);
1005 handle->mirrorlist_fd = fd;
1006
1007 lr_mirrorlist_free(ml);
1008
1009 g_debug("%s: Mirrorlist parsed", __func__);
1010 return TRUE;
1011 }
1012
1013 static gboolean
lr_handle_prepare_metalink(LrHandle * handle,gchar * localpath,GError ** err)1014 lr_handle_prepare_metalink(LrHandle *handle, gchar *localpath, GError **err)
1015 {
1016 assert(handle->metalink_fd == -1);
1017 assert(!handle->metalink_mirrors);
1018 assert(!handle->metalink);
1019
1020 int fd = -1;
1021
1022 // Get file descriptor with content
1023
1024 if (!localpath && !handle->metalinkurl) {
1025 // Nothing to do
1026 return TRUE;
1027 } else if (localpath && !handle->metalinkurl) {
1028 // Just try to use metalink of the local repository
1029 _cleanup_free_ gchar *path = lr_pathconcat(localpath, "metalink.xml", NULL);
1030
1031 if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) {
1032 g_debug("%s: Local metalink.xml found at %s", __func__, path);
1033 fd = open(path, O_RDONLY);
1034 if (fd < 0) {
1035 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1036 "Cannot open %s: %s",
1037 path, g_strerror(errno));
1038 return FALSE;
1039 }
1040 } else {
1041 // No local metalink
1042 return TRUE;
1043 }
1044 } else if (!handle->metalinkurl) {
1045 // Nothing to do
1046 return TRUE;
1047 } else if (handle->offline && !lr_is_local_path(handle->metalinkurl)) {
1048 // We should work offline, ignore remote mirrorlist
1049 g_debug("%s: LRO_OFFLINE used, remote metalink ignored: %s",
1050 __func__, handle->metalinkurl);
1051 return TRUE;
1052 } else if (handle->local && !lr_is_local_path(handle->metalinkurl)) {
1053 // We should work only locally, ignore remote mirrorlist
1054 g_debug("%s: LRO_LOCAL used, remote metalink ignored: %s",
1055 __func__, handle->metalinkurl);
1056 return TRUE;
1057 } else if (handle->metalinkurl) {
1058 // Download remote metalink
1059 _cleanup_free_ gchar *url = NULL;
1060
1061 fd = lr_gettmpfile();
1062 if (fd < 0) {
1063 g_debug("%s: Cannot create a temporary file", __func__);
1064 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1065 "Cannot create a temporary file");
1066 return FALSE;
1067 }
1068
1069 url = lr_prepend_url_protocol(handle->metalinkurl);
1070 handle->onetimeflag_apply = TRUE;
1071 if (!lr_yum_download_url_retry(3, handle, url, fd, TRUE, FALSE, err)) {
1072 close(fd);
1073 return FALSE;
1074 }
1075
1076 if (lseek(fd, 0, SEEK_SET) != 0) {
1077 g_debug("%s: Seek error: %s", __func__, g_strerror(errno));
1078 g_set_error(err, LR_HANDLE_ERROR, LRE_IO,
1079 "lseek(%d, 0, SEEK_SET) error: %s",
1080 fd, g_strerror(errno));
1081 close(fd);
1082 return FALSE;
1083 }
1084 }
1085
1086 assert(fd >= 0);
1087
1088 // Parse the file descriptor content
1089
1090 g_debug("%s: Parsing metalink.xml", __func__);
1091
1092 gchar *metalink_file = "";
1093 gchar *metalink_suffix = NULL;
1094 if (handle->repotype == LR_YUMREPO) {
1095 metalink_file = "repomd.xml";
1096 metalink_suffix = "repodata/repomd.xml";
1097 }
1098
1099 LrMetalink *ml = lr_metalink_init();
1100 gboolean ret = lr_metalink_parse_file(ml,
1101 fd,
1102 metalink_file,
1103 lr_xml_parser_warning_logger,
1104 "Metalink xml parser",
1105 err);
1106 if (!ret) {
1107 g_warning("Error while parsing metalink");
1108 close(fd);
1109 lr_metalink_free(ml);
1110 return FALSE;
1111 }
1112
1113 if (!ml->urls) {
1114 g_debug("%s: No URLs in metalink", __func__);
1115 g_set_error(err, LR_HANDLE_ERROR, LRE_MLBAD, "No URLs in metalink");
1116 close(fd);
1117 lr_metalink_free(ml);
1118 return FALSE;
1119 }
1120
1121 // List parsed mirrors
1122 g_debug("%s: Mirrors from metalink:", __func__);
1123 for (GSList *elem = ml->urls; elem; elem = g_slist_next(elem))
1124 g_debug(" %s", ((LrMetalinkUrl *) elem->data)->url);
1125
1126 // Convert metalink to internal mirrorlist format
1127
1128 handle->metalink_mirrors = lr_lrmirrorlist_append_metalink(
1129 NULL,
1130 ml,
1131 metalink_suffix,
1132 handle->urlvars);
1133 handle->metalink_fd = fd;
1134 handle->metalink = ml;
1135
1136 g_debug("%s: Metalink parsed", __func__);
1137 return TRUE;
1138 }
1139
1140 gboolean
lr_handle_prepare_internal_mirrorlist(LrHandle * handle,gboolean usefastestmirror,GError ** err)1141 lr_handle_prepare_internal_mirrorlist(LrHandle *handle,
1142 gboolean usefastestmirror,
1143 GError **err)
1144 {
1145 assert(!err || *err == NULL);
1146
1147 if (handle->internal_mirrorlist)
1148 return TRUE; // Internal mirrorlist already exists
1149
1150 // Create internal mirrorlist
1151
1152 g_debug("%s: Preparing internal mirrorlist", __func__);
1153
1154 // Get local path in case of local repository
1155 gchar *local_path = NULL;
1156 if (handle->urls && handle->urls[0]) {
1157 // If first base URL is local path, get that path
1158 // (without file: or file:// prefix if specified)
1159 gchar *url = handle->urls[0];
1160 if (g_str_has_prefix(url, "file://"))
1161 local_path = url + 7;
1162 else if (g_str_has_prefix(url, "file:")) // RFC 3986
1163 local_path = url + 5;
1164 else if (!strstr(url, "://"))
1165 local_path = url;
1166 }
1167
1168 // Since urls, mirrorlists and metalinks are not exclusive its
1169 // sufficient for at least on of the three to succeed in order to
1170 // continue. In the case where all of present ones fail we propagate
1171 // only the last error, because GError cannot handle multiple
1172 // errors at the same time.
1173
1174 gboolean ret_urls = FALSE;
1175 gboolean ret_mirrorlist = FALSE;
1176 gboolean ret_metalink = FALSE;
1177 gboolean at_least_one_present = FALSE;
1178 GError *tmp_err = NULL;
1179
1180 // LRO_URLS
1181 if (!handle->urls_mirrors && handle->urls) {
1182 at_least_one_present = TRUE;
1183 ret_urls = lr_handle_prepare_urls(handle, &tmp_err);
1184 if (!ret_urls) {
1185 assert(tmp_err);
1186 g_warning("LRO_URLS processing failed: %s", tmp_err->message);
1187 }
1188 }
1189
1190 // LRO_MIRRORLISTURL
1191 if (!handle->mirrorlist_mirrors && (handle->mirrorlisturl || local_path)) {
1192 g_clear_error(&tmp_err);
1193 at_least_one_present = TRUE;
1194 ret_mirrorlist = lr_handle_prepare_mirrorlist(handle, local_path, &tmp_err);
1195 if (!ret_mirrorlist) {
1196 assert(tmp_err);
1197 g_warning("LRO_MIRRORLISTURL processing failed: %s", tmp_err->message);
1198 }
1199 }
1200
1201 // LRO_METALINKURL
1202 if (!handle->metalink_mirrors && (handle->metalinkurl || local_path)) {
1203 g_clear_error(&tmp_err);
1204 at_least_one_present = TRUE;
1205 ret_metalink = lr_handle_prepare_metalink(handle, local_path, &tmp_err);
1206 if (!ret_metalink) {
1207 assert(tmp_err);
1208 g_warning("LRO_METALINKURL processing failed: %s", tmp_err->message);
1209 }
1210 }
1211
1212 if (!ret_urls && !ret_mirrorlist && !ret_metalink && at_least_one_present) {
1213 g_propagate_error(err, tmp_err);
1214 return FALSE;
1215 }
1216
1217 // Append all the mirrorlist to the single internal mirrorlist
1218 // This internal mirrorlist is used for downloading
1219 // Note: LRO_MIRRORLISTURL and LRO_METALINKURL lists are included
1220 // to this list only if they are explicitly specified (lists
1221 // implicitly loaded from a local repository are not included)
1222
1223 g_debug("%s: Finalizing internal mirrorlist", __func__);
1224
1225 // Mirrorlist from the LRO_MIRRORLISTURL
1226 if (handle->mirrorlisturl)
1227 handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1228 handle->internal_mirrorlist,
1229 handle->mirrorlist_mirrors);
1230
1231 // Mirrorlist from the LRO_METALINKURL
1232 if (handle->metalinkurl)
1233 handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1234 handle->internal_mirrorlist,
1235 handle->metalink_mirrors);
1236
1237 // Mirrorlist from the LRO_URLS
1238 handle->internal_mirrorlist = lr_lrmirrorlist_append_lrmirrorlist(
1239 handle->internal_mirrorlist,
1240 handle->urls_mirrors);
1241
1242 // If enabled, sort internal mirrorlist by the connection
1243 // speed (the LRO_FASTESTMIRROR option)
1244 if (usefastestmirror) {
1245 g_debug("%s: Sorting internal mirrorlist by connection speed",
1246 __func__);
1247 gboolean ret = lr_fastestmirror_sort_internalmirrorlist(handle, err);
1248 if (!ret)
1249 return FALSE;
1250 }
1251
1252 // Prepare mirrors (the list that is reported via LRI_MIRRORS)
1253 // This list contains mirrors from mirrorlist and/or metalink
1254 // even if they are not explicitly specified, but are available
1255 // in a local repo (that is specified at the first url of LRO_URLS)
1256
1257 g_debug("%s: Finalizing mirrors reported via LRI_MIRRORS", __func__);
1258
1259 handle->mirrors = lr_lrmirrorlist_append_lrmirrorlist(
1260 handle->mirrors,
1261 handle->mirrorlist_mirrors);
1262 handle->mirrors = lr_lrmirrorlist_append_lrmirrorlist(
1263 handle->mirrors,
1264 handle->metalink_mirrors);
1265
1266 return TRUE;
1267 }
1268
1269 gboolean
lr_handle_perform(LrHandle * handle,LrResult * result,GError ** err)1270 lr_handle_perform(LrHandle *handle, LrResult *result, GError **err)
1271 {
1272 int ret = TRUE;
1273 GError *tmp_err = NULL;
1274
1275 assert(handle);
1276 assert(!err || *err == NULL);
1277
1278 if (!result) {
1279 g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1280 "No result argument passed");
1281 return FALSE;
1282 }
1283
1284 if (!handle->urls && !handle->mirrorlisturl && !handle->metalinkurl) {
1285 g_set_error(err, LR_HANDLE_ERROR, LRE_NOURL,
1286 "No LRO_URLS, LRO_MIRRORLISTURL nor LRO_METALINKURL specified");
1287 return FALSE;
1288 }
1289
1290 if (handle->repotype != LR_YUMREPO) {
1291 g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1292 "Bad LRO_REPOTYPE specified");
1293 return FALSE;
1294 }
1295
1296 /* Setup destination directory */
1297 if (handle->update) {
1298 if (!result->destdir) {
1299 g_set_error(err, LR_HANDLE_ERROR, LRE_INCOMPLETERESULT,
1300 "Incomplete result object, destdir is missing");
1301 return FALSE;
1302 }
1303 lr_free(handle->destdir);
1304 handle->destdir = g_strdup(result->destdir);
1305 } else if (!handle->destdir && !handle->local) {
1306 handle->destdir = g_strdup(TMP_DIR_TEMPLATE);
1307 if (!mkdtemp(handle->destdir)) {
1308 g_set_error(err, LR_HANDLE_ERROR, LRE_CANNOTCREATETMP,
1309 "Cannot create tmpdir: %s", g_strerror(errno));
1310 return FALSE;
1311 }
1312 }
1313
1314 g_debug("%s: Using dir: %s", __func__, handle->destdir);
1315
1316 struct sigaction old_sigact;
1317 if (handle->interruptible) {
1318 /* Setup sighandler */
1319 struct sigaction sigact;
1320 g_debug("%s: Using own SIGINT handler", __func__);
1321 memset(&sigact, 0, sizeof(old_sigact));
1322 memset(&sigact, 0, sizeof(sigact));
1323 sigemptyset(&sigact.sa_mask);
1324 sigact.sa_handler = lr_sigint_handler;
1325 sigaddset(&sigact.sa_mask, SIGINT);
1326 sigact.sa_flags = 0;
1327 if (sigaction(SIGINT, &sigact, &old_sigact) == -1) {
1328 g_set_error(err, LR_HANDLE_ERROR, LRE_SIGACTION,
1329 "sigaction(SIGINT,,) error");
1330 return FALSE;
1331 }
1332 }
1333
1334 ret = lr_handle_prepare_internal_mirrorlist(handle,
1335 handle->fastestmirror,
1336 &tmp_err);
1337 if (!ret) {
1338 g_debug("Cannot prepare internal mirrorlist: %s", tmp_err->message);
1339 g_propagate_prefixed_error(err, tmp_err,
1340 "Cannot prepare internal mirrorlist: ");
1341 return FALSE;
1342 }
1343
1344 if (handle->fetchmirrors) {
1345 /* Only download and parse mirrorlist */
1346 g_debug("%s: Only fetching mirrorlist/metalink", __func__);
1347 } else {
1348 /* Do the other stuff */
1349 switch (handle->repotype) {
1350 case LR_YUMREPO:
1351 g_debug("%s: Downloading/Locating yum repo", __func__);
1352 ret = lr_yum_perform(handle, result, &tmp_err);
1353 break;
1354 default:
1355 g_debug("%s: Bad repo type", __func__);
1356 assert(0);
1357 ret = FALSE;
1358 g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1359 "Bad repo type: %d", handle->repotype);
1360 break;
1361 }
1362 }
1363
1364 if (handle->interruptible) {
1365 /* Restore signal handler */
1366 g_debug("%s: Restoring an old SIGINT handler", __func__);
1367 sigaction(SIGINT, &old_sigact, NULL);
1368
1369 if (lr_interrupt) {
1370 g_set_error(err, LR_HANDLE_ERROR, LRE_INTERRUPTED,
1371 "Librepo was interrupted by a signal");
1372 if (tmp_err)
1373 g_error_free(tmp_err);
1374 return FALSE;
1375 }
1376 }
1377
1378 assert((ret && !tmp_err) || (!ret && tmp_err));
1379
1380 if (tmp_err)
1381 g_propagate_error(err, tmp_err);
1382
1383 return ret;
1384 }
1385
1386 gboolean
lr_handle_getinfo(LrHandle * handle,GError ** err,LrHandleInfoOption option,...)1387 lr_handle_getinfo(LrHandle *handle,
1388 GError **err,
1389 LrHandleInfoOption option,
1390 ...)
1391 {
1392 gboolean rc = TRUE;
1393 va_list arg;
1394 char **str;
1395 long *lnum;
1396 double *dnum;
1397
1398 assert(!err || *err == NULL);
1399
1400 if (!handle) {
1401 g_set_error(err, LR_HANDLE_ERROR, LRE_BADFUNCARG,
1402 "No handle specified");
1403 return FALSE;
1404 }
1405
1406 va_start(arg, option);
1407
1408 switch (option) {
1409
1410 case LRI_UPDATE:
1411 lnum = va_arg(arg, long *);
1412 *lnum = (long) handle->update;
1413 break;
1414
1415 case LRI_MIRRORLIST:
1416 str = va_arg(arg, char **);
1417 *str = handle->mirrorlist;
1418 break;
1419
1420 case LRI_MIRRORLISTURL:
1421 str = va_arg(arg, char **);
1422 *str = handle->mirrorlisturl;
1423 break;
1424
1425 case LRI_METALINKURL:
1426 str = va_arg(arg, char **);
1427 *str = handle->metalinkurl;
1428 break;
1429
1430 case LRI_LOCAL:
1431 lnum = va_arg(arg, long *);
1432 *lnum = (long) handle->local;
1433 break;
1434
1435 case LRI_PROGRESSCB: {
1436 LrProgressCb *cb= va_arg(arg, LrProgressCb *);
1437 *cb = handle->user_cb;
1438 break;
1439 }
1440
1441 case LRI_PROGRESSDATA: {
1442 void **data = va_arg(arg, void **);
1443 *data = handle->user_data;
1444 break;
1445 }
1446
1447 case LRI_DESTDIR:
1448 str = va_arg(arg, char **);
1449 *str = handle->destdir;
1450 break;
1451
1452 case LRI_REPOTYPE:
1453 lnum = va_arg(arg, long *);
1454 *lnum = (long) handle->repotype;
1455 break;
1456
1457 case LRI_USERAGENT:
1458 str = va_arg(arg, char **);
1459 *str = handle->useragent;
1460 break;
1461
1462 case LRI_URLS:
1463 case LRI_YUMDLIST:
1464 case LRI_YUMBLIST:
1465 case LRI_HTTPHEADER: {
1466 char **source_list = NULL;
1467 char ***strlist = va_arg(arg, char ***);
1468
1469 if (option == LRI_URLS)
1470 source_list = handle->urls;
1471 else if (option == LRI_YUMDLIST)
1472 source_list = handle->yumdlist;
1473 else if (option == LRI_YUMBLIST)
1474 source_list = handle->yumblist;
1475 else if (option == LRI_HTTPHEADER)
1476 source_list = handle->httpheader;
1477
1478 if (!source_list) {
1479 *strlist = NULL;
1480 break;
1481 }
1482
1483 *strlist = lr_strv_dup(source_list);
1484 break;
1485 }
1486
1487 case LRI_FETCHMIRRORS:
1488 lnum = va_arg(arg, long *);
1489 *lnum = (long) handle->fetchmirrors;
1490 break;
1491
1492 case LRI_MAXMIRRORTRIES:
1493 lnum = va_arg(arg, long *);
1494 *lnum = (long) handle->maxmirrortries;
1495 break;
1496
1497 case LRI_YUMSLIST: {
1498 LrUrlVars **slist = va_arg(arg, LrUrlVars **);
1499 *slist = handle->yumslist;
1500 break;
1501 }
1502
1503 case LRI_VARSUB: {
1504 LrUrlVars **vars = va_arg(arg, LrUrlVars **);
1505 *vars = handle->urlvars;
1506 break;
1507 }
1508
1509 case LRI_MIRRORS: {
1510 int x;
1511 char ***list = va_arg(arg, char ***);
1512 *list = NULL;
1513 LrInternalMirrorlist *ml = handle->mirrors;
1514
1515 if (!ml)
1516 // lr_handle_perform() or lr_download_package() was not called yet
1517 break;
1518
1519 /* Make list of urls from internal mirrorlist */
1520 x = 0;
1521 *list = lr_malloc((g_slist_length(ml) + 1) * sizeof(char *));
1522 for (LrInternalMirrorlist *elem = ml; elem; elem = g_slist_next(elem)) {
1523 LrInternalMirror *mirror = elem->data;
1524 (*list)[x] = g_strdup(mirror->url);
1525 x++;
1526 }
1527 (*list)[x] = NULL;
1528 break;
1529 }
1530
1531 case LRI_METALINK: {
1532 LrMetalink **metalink = va_arg(arg, LrMetalink **);
1533 *metalink = handle->metalink;
1534 break;
1535 }
1536
1537 case LRI_FASTESTMIRROR:
1538 lnum = va_arg(arg, long *);
1539 *lnum = (long) handle->fastestmirror;
1540 break;
1541
1542 case LRI_FASTESTMIRRORCACHE:
1543 str = va_arg(arg, char **);
1544 *str = handle->fastestmirrorcache;
1545 break;
1546
1547 case LRI_FASTESTMIRRORMAXAGE:
1548 lnum = va_arg(arg, long *);
1549 *lnum = (long) handle->fastestmirrormaxage;
1550 break;
1551
1552 case LRI_HMFCB: {
1553 LrHandleMirrorFailureCb *cb= va_arg(arg, LrHandleMirrorFailureCb *);
1554 *cb = handle->hmfcb;
1555 break;
1556 }
1557
1558 case LRI_SSLVERIFYPEER:
1559 lnum = va_arg(arg, long *);
1560 *lnum = (long) handle->sslverifypeer;
1561 break;
1562
1563 case LRI_SSLVERIFYSTATUS:
1564 lnum = va_arg(arg, long *);
1565 *lnum = (long) handle->sslverifystatus;
1566 break;
1567
1568
1569 case LRI_SSLVERIFYHOST:
1570 lnum = va_arg(arg, long *);
1571 *lnum = (long) (handle->sslverifyhost ? 1 : 0);
1572 break;
1573
1574 case LRI_SSLCLIENTCERT:
1575 str = va_arg(arg, char **);
1576 *str = handle->sslclientcert;
1577 break;
1578
1579 case LRI_SSLCLIENTKEY:
1580 str = va_arg(arg, char **);
1581 *str = handle->sslclientkey;
1582 break;
1583
1584 case LRI_SSLCACERT:
1585 str = va_arg(arg, char **);
1586 *str = handle->sslcacert;
1587 break;
1588
1589 case LRI_PROXY_SSLVERIFYPEER:
1590 lnum = va_arg(arg, long *);
1591 *lnum = (long) handle->proxy_sslverifypeer;
1592 break;
1593
1594 case LRI_PROXY_SSLVERIFYHOST:
1595 lnum = va_arg(arg, long *);
1596 *lnum = (long) (handle->proxy_sslverifyhost ? 1 : 0);
1597 break;
1598
1599 case LRI_PROXY_SSLCLIENTCERT:
1600 str = va_arg(arg, char **);
1601 *str = handle->proxy_sslclientcert;
1602 break;
1603
1604 case LRI_PROXY_SSLCLIENTKEY:
1605 str = va_arg(arg, char **);
1606 *str = handle->proxy_sslclientkey;
1607 break;
1608
1609 case LRI_PROXY_SSLCACERT:
1610 str = va_arg(arg, char **);
1611 *str = handle->proxy_sslcacert;
1612 break;
1613
1614 case LRI_IPRESOLVE: {
1615 LrIpResolveType *type = va_arg(arg, LrIpResolveType *);
1616 *type = (LrIpResolveType) (handle->ipresolve);
1617 break;
1618 }
1619
1620 case LRI_ALLOWEDMIRRORFAILURES:
1621 lnum = va_arg(arg, long *);
1622 *lnum = (long) (handle->allowed_mirror_failures);
1623 break;
1624
1625 case LRI_ADAPTIVEMIRRORSORTING:
1626 lnum = va_arg(arg, long *);
1627 *lnum = (long) (handle->adaptivemirrorsorting);
1628 break;
1629
1630 case LRI_GNUPGHOMEDIR:
1631 str = va_arg(arg, char **);
1632 *str = handle->gnupghomedir;
1633 break;
1634
1635 case LRI_FASTESTMIRRORTIMEOUT:
1636 dnum = va_arg(arg, double *);
1637 *dnum = (double) handle->fastestmirrortimeout;
1638 break;
1639
1640 case LRI_OFFLINE:
1641 lnum = va_arg(arg, long *);
1642 *lnum = (long) handle->offline;
1643 break;
1644
1645 case LRI_LOWSPEEDTIME:
1646 lnum = va_arg(arg, long *);
1647 *lnum = (long) (handle->lowspeedtime);
1648 break;
1649
1650 case LRI_LOWSPEEDLIMIT:
1651 lnum = va_arg(arg, long *);
1652 *lnum = (long) (handle->lowspeedlimit);
1653 break;
1654
1655 case LRI_HTTPAUTHMETHODS: {
1656 LrAuth *auth = va_arg(arg, LrAuth *);
1657 *auth = handle->httpauthmethods;
1658 break;
1659 }
1660
1661 case LRI_PROXYAUTHMETHODS: {
1662 LrAuth *auth = va_arg(arg, LrAuth *);
1663 *auth = handle->proxyauthmethods;
1664 break;
1665 }
1666
1667 case LRI_FTPUSEEPSV:
1668 lnum = va_arg(arg, long *);
1669 *lnum = (long) handle->ftpuseepsv;
1670 break;
1671
1672 case LRI_CACHEDIR:
1673 str = va_arg(arg, char **);
1674 *str = handle->cachedir;
1675 break;
1676
1677 default:
1678 rc = FALSE;
1679 g_set_error(err, LR_HANDLE_ERROR, LRE_UNKNOWNOPT,
1680 "Unknown option");
1681 break;
1682 }
1683
1684 va_end(arg);
1685 return rc;
1686 }
1687