XBPS Library API 20240111
The X Binary Package System
repo.c
1/*-
2 * Copyright (c) 2012-2020 Juan Romero Pardines.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
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 ``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 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#include <errno.h>
27#include <fcntl.h>
28#include <libgen.h>
29#include <stdbool.h>
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include <archive.h>
35#include <archive_entry.h>
36
37#include <openssl/err.h>
38#include <openssl/sha.h>
39#include <openssl/rsa.h>
40#include <openssl/ssl.h>
41#include <openssl/pem.h>
42
43#include "xbps_api_impl.h"
44
45/**
46 * @file lib/repo.c
47 * @brief Repository functions
48 * @defgroup repo Repository functions
49 */
50char *
51xbps_repo_path(struct xbps_handle *xhp, const char *url)
52{
53 return xbps_repo_path_with_name(xhp, url, "repodata");
54}
55
56char *
57xbps_repo_path_with_name(struct xbps_handle *xhp, const char *url, const char *name)
58{
59 assert(xhp);
60 assert(url);
61 assert(strcmp(name, "repodata") == 0 || strcmp(name, "stagedata") == 0);
62
63 return xbps_xasprintf("%s/%s-%s",
64 url, xhp->target_arch ? xhp->target_arch : xhp->native_arch, name);
65}
66
67static xbps_dictionary_t
68repo_get_dict(struct xbps_repo *repo)
69{
70 struct archive_entry *entry;
71 int rv;
72
73 if (repo->ar == NULL)
74 return NULL;
75
76 rv = archive_read_next_header(repo->ar, &entry);
77 if (rv != ARCHIVE_OK) {
78 xbps_dbg_printf("%s: read_next_header %s\n", repo->uri,
79 archive_error_string(repo->ar));
80 return NULL;
81 }
82 return xbps_archive_get_dictionary(repo->ar, entry);
83}
84
85bool
86xbps_repo_lock(struct xbps_handle *xhp, const char *repodir,
87 int *lockfd, char **lockfname)
88{
89 char *repofile, *lockfile;
90 int fd, rv;
91
92 assert(repodir);
93 assert(lockfd);
94 assert(lockfname);
95
96 repofile = xbps_repo_path(xhp, repodir);
97 assert(repofile);
98
99 lockfile = xbps_xasprintf("%s.lock", repofile);
100 free(repofile);
101
102 for (;;) {
103 fd = open(lockfile, O_WRONLY|O_CREAT|O_EXCL|O_CLOEXEC, 0660);
104 rv = errno;
105 if (fd != -1)
106 break;
107 if (rv != EEXIST) {
108 xbps_dbg_printf("[repo] `%s' failed to "
109 "create lock file %s\n", lockfile, strerror(rv));
110 free(lockfile);
111 return false;
112 } else {
113 xbps_dbg_printf("[repo] `%s' lock file exists,"
114 "waiting for 1s...\n", lockfile);
115 sleep(1);
116 }
117 }
118 *lockfname = lockfile;
119 *lockfd = fd;
120 return true;
121}
122
123void
124xbps_repo_unlock(int lockfd, char *lockfname)
125{
126 if (lockfd != -1) {
127 close(lockfd);
128 }
129 if (lockfname) {
130 unlink(lockfname);
131 free(lockfname);
132 }
133}
134
135static bool
136repo_open_local(struct xbps_repo *repo, const char *repofile)
137{
138 struct stat st;
139
140 if (fstat(repo->fd, &st) == -1) {
141 xbps_dbg_printf("[repo] `%s' fstat repodata %s\n",
142 repofile, strerror(errno));
143 return false;
144 }
145
146 repo->ar = archive_read_new();
147 assert(repo->ar);
148 archive_read_support_filter_gzip(repo->ar);
149 archive_read_support_filter_bzip2(repo->ar);
150 archive_read_support_filter_xz(repo->ar);
151 archive_read_support_filter_lz4(repo->ar);
152 archive_read_support_filter_zstd(repo->ar);
153 archive_read_support_format_tar(repo->ar);
154
155 if (archive_read_open_fd(repo->ar, repo->fd, st.st_blksize) == ARCHIVE_FATAL) {
156 xbps_dbg_printf("[repo] `%s' failed to open repodata archive %s\n",
157 repofile, archive_error_string(repo->ar));
158 return false;
159 }
160 if ((repo->idx = repo_get_dict(repo)) == NULL) {
161 xbps_dbg_printf("[repo] `%s' failed to internalize "
162 " index on archive, removing file.\n", repofile);
163 /* broken archive, remove it */
164 (void)unlink(repofile);
165 return false;
166 }
167 xbps_dictionary_make_immutable(repo->idx);
168 repo->idxmeta = repo_get_dict(repo);
169 if (repo->idxmeta != NULL) {
170 repo->is_signed = true;
171 xbps_dictionary_make_immutable(repo->idxmeta);
172 }
173 /*
174 * We don't need the archive anymore, we are only
175 * interested in the proplib dictionaries.
176 */
177 xbps_repo_close(repo);
178
179 return true;
180}
181
182static bool
183repo_open_remote(struct xbps_repo *repo)
184{
185 char *rpath;
186 bool rv;
187
188 rpath = xbps_repo_path(repo->xhp, repo->uri);
189 rv = xbps_repo_fetch_remote(repo, rpath);
190 free(rpath);
191 if (rv) {
192 xbps_dbg_printf("[repo] `%s' used remotely (kept in memory).\n", repo->uri);
193 if (repo->xhp->state_cb && xbps_repo_key_import(repo) != 0)
194 rv = false;
195 }
196 return rv;
197}
198
199static struct xbps_repo *
200repo_open_with_type(struct xbps_handle *xhp, const char *url, const char *name)
201{
202 struct xbps_repo *repo = NULL;
203 const char *arch;
204 char *repofile = NULL;
205
206 assert(xhp);
207 assert(url);
208
209 if (xhp->target_arch)
210 arch = xhp->target_arch;
211 else
212 arch = xhp->native_arch;
213
214 repo = calloc(1, sizeof(struct xbps_repo));
215 assert(repo);
216 repo->fd = -1;
217 repo->xhp = xhp;
218 repo->uri = url;
219
220 if (xbps_repository_is_remote(url)) {
221 /* remote repository */
222 char *rpath;
223
224 if ((rpath = xbps_get_remote_repo_string(url)) == NULL) {
225 goto out;
226 }
227 repofile = xbps_xasprintf("%s/%s/%s-%s", xhp->metadir, rpath, arch, name);
228 free(rpath);
229 repo->is_remote = true;
230 } else {
231 /* local repository */
232 repofile = xbps_repo_path_with_name(xhp, url, name);
233 }
234 /*
235 * In memory repo sync.
236 */
237 if (repo->is_remote && (xhp->flags & XBPS_FLAG_REPOS_MEMSYNC)) {
238 if (repo_open_remote(repo)) {
239 free(repofile);
240 return repo;
241 }
242 goto out;
243 }
244 /*
245 * Open the repository archive.
246 */
247 repo->fd = open(repofile, O_RDONLY|O_CLOEXEC);
248 if (repo->fd == -1) {
249 int rv = errno;
250 xbps_dbg_printf("[repo] `%s' open %s %s\n",
251 repofile, name, strerror(rv));
252 xbps_error_printf("%s: %s\n", strerror(rv), repofile);
253 goto out;
254 }
255 if (repo_open_local(repo, repofile)) {
256 free(repofile);
257 return repo;
258 }
259
260out:
261 free(repofile);
262 xbps_repo_release(repo);
263 return NULL;
264}
265
266bool
267xbps_repo_store(struct xbps_handle *xhp, const char *repo)
268{
269 char *url = NULL;
270
271 assert(xhp);
272 assert(repo);
273
274 if (xhp->repositories == NULL) {
275 xhp->repositories = xbps_array_create();
276 assert(xhp->repositories);
277 }
278 /*
279 * If it's a local repo and path is relative, make it absolute.
280 */
281 if (!xbps_repository_is_remote(repo)) {
282 if (repo[0] != '/' && repo[0] != '\0') {
283 if ((url = realpath(repo, NULL)) == NULL)
284 xbps_dbg_printf("[repo] %s: realpath %s\n", __func__, repo);
285 }
286 }
287 if (xbps_match_string_in_array(xhp->repositories, url ? url : repo)) {
288 xbps_dbg_printf("[repo] `%s' already stored\n", url ? url : repo);
289 if (url)
290 free(url);
291 return false;
292 }
293 if (xbps_array_add_cstring(xhp->repositories, url ? url : repo)) {
294 xbps_dbg_printf("[repo] `%s' stored successfully\n", url ? url : repo);
295 if (url)
296 free(url);
297 return true;
298 }
299 if (url)
300 free(url);
301
302 return false;
303}
304
305bool
306xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
307{
308 char *url;
309 bool rv = false;
310
311 assert(xhp);
312 assert(repo);
313
314 if (xhp->repositories == NULL)
315 return false;
316
317 url = strdup(repo);
319 if (url)
320 xbps_dbg_printf("[repo] `%s' removed\n", url);
321 rv = true;
322 }
323 free(url);
324
325 return rv;
326}
327
328struct xbps_repo *
329xbps_repo_stage_open(struct xbps_handle *xhp, const char *url)
330{
331 return repo_open_with_type(xhp, url, "stagedata");
332}
333
334struct xbps_repo *
335xbps_repo_public_open(struct xbps_handle *xhp, const char *url) {
336 return repo_open_with_type(xhp, url, "repodata");
337}
338
339struct xbps_repo *
340xbps_repo_open(struct xbps_handle *xhp, const char *url)
341{
342 struct xbps_repo *repo = xbps_repo_public_open(xhp, url);
343 struct xbps_repo *stage = NULL;
344 xbps_dictionary_t idx;
345 const char *pkgname;
346 xbps_object_t keysym;
347 xbps_object_iterator_t iter;
348 /*
349 * Load and merge staging repository if the repository is local.
350 */
351 if (repo && !repo->is_remote) {
352 stage = xbps_repo_stage_open(xhp, url);
353 if (stage == NULL)
354 return repo;
355 idx = xbps_dictionary_copy_mutable(repo->idx);
356 iter = xbps_dictionary_iterator(stage->idx);
357 while ((keysym = xbps_object_iterator_next(iter))) {
358 pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym);
359 xbps_dictionary_set(idx, pkgname,
360 xbps_dictionary_get_keysym(stage->idx, keysym));
361 }
362 xbps_object_iterator_release(iter);
363 xbps_object_release(repo->idx);
364 xbps_repo_release(stage);
365 repo->idx = idx;
366 return repo;
367 }
368 return repo;
369}
370
371void
373{
374 if (!repo)
375 return;
376
377 if (repo->ar != NULL) {
378 archive_read_free(repo->ar);
379 repo->ar = NULL;
380 }
381 if (repo->fd != -1) {
382 close(repo->fd);
383 repo->fd = -1;
384 }
385}
386
387void
389{
390 if (!repo)
391 return;
392
393 xbps_repo_close(repo);
394
395 if (repo->idx != NULL) {
396 xbps_object_release(repo->idx);
397 repo->idx = NULL;
398 }
399 if (repo->idxmeta != NULL) {
400 xbps_object_release(repo->idxmeta);
401 repo->idxmeta = NULL;
402 }
403 free(repo);
404}
405
406xbps_dictionary_t
407xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
408{
409 xbps_dictionary_t pkgd;
410 const char *pkgver;
411 char pkgname[XBPS_NAME_SIZE] = {0};
412
413 if (!repo || !repo->idx || !pkg) {
414 return NULL;
415 }
416 pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
417 if (!pkgd) {
418 return NULL;
419 }
420 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
421 return pkgd;
422 }
423 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
424 return NULL;
425 }
426 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
427 return NULL;
428 }
429 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
430 return NULL;
431 }
432 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
433 return NULL;
434 }
435 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
436
437 return pkgd;
438}
439
440xbps_dictionary_t
441xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
442{
443 xbps_dictionary_t pkgd = NULL;
444 const char *pkgver;
445 char pkgname[XBPS_NAME_SIZE] = {0};
446
447 if (!repo || !repo->idx || !pkg) {
448 return NULL;
449 }
450 /* Try matching vpkg from configuration files */
451 if ((pkgd = xbps_find_virtualpkg_in_conf(repo->xhp, repo->idx, pkg))) {
452 goto add;
453 }
454 /* ... otherwise match a real pkg */
455 if ((pkgd = xbps_find_pkg_in_dict(repo->idx, pkg))) {
456 goto add;
457 }
458 return NULL;
459add:
460 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
461 return pkgd;
462 }
463 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
464 return NULL;
465 }
466 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
467 return NULL;
468 }
469 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
470 return NULL;
471 }
472 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
473 return NULL;
474 }
475 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
476 return pkgd;
477}
478
479static xbps_array_t
480revdeps_match(struct xbps_repo *repo, xbps_dictionary_t tpkgd, const char *str)
481{
482 xbps_dictionary_t pkgd;
483 xbps_array_t revdeps = NULL, pkgdeps, provides;
484 xbps_object_iterator_t iter;
485 xbps_object_t obj;
486 const char *pkgver = NULL, *tpkgver = NULL, *arch = NULL, *vpkg = NULL;
487
488 iter = xbps_dictionary_iterator(repo->idx);
489 assert(iter);
490
491 while ((obj = xbps_object_iterator_next(iter))) {
492 pkgd = xbps_dictionary_get_keysym(repo->idx, obj);
493 if (xbps_dictionary_equals(pkgd, tpkgd))
494 continue;
495
496 pkgdeps = xbps_dictionary_get(pkgd, "run_depends");
497 if (!xbps_array_count(pkgdeps))
498 continue;
499 /*
500 * Try to match passed in string.
501 */
502 if (str) {
503 if (!xbps_match_pkgdep_in_array(pkgdeps, str))
504 continue;
505 xbps_dictionary_get_cstring_nocopy(pkgd,
506 "architecture", &arch);
507 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
508 continue;
509
510 xbps_dictionary_get_cstring_nocopy(pkgd,
511 "pkgver", &tpkgver);
512 /* match */
513 if (revdeps == NULL)
514 revdeps = xbps_array_create();
515
516 if (!xbps_match_string_in_array(revdeps, tpkgver))
517 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
518
519 continue;
520 }
521 /*
522 * Try to match any virtual package.
523 */
524 provides = xbps_dictionary_get(tpkgd, "provides");
525 for (unsigned int i = 0; i < xbps_array_count(provides); i++) {
526 xbps_array_get_cstring_nocopy(provides, i, &vpkg);
527 if (!xbps_match_pkgdep_in_array(pkgdeps, vpkg))
528 continue;
529
530 xbps_dictionary_get_cstring_nocopy(pkgd,
531 "architecture", &arch);
532 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
533 continue;
534
535 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver",
536 &tpkgver);
537 /* match */
538 if (revdeps == NULL)
539 revdeps = xbps_array_create();
540
541 if (!xbps_match_string_in_array(revdeps, tpkgver))
542 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
543 }
544 /*
545 * Try to match by pkgver.
546 */
547 xbps_dictionary_get_cstring_nocopy(tpkgd, "pkgver", &pkgver);
548 if (!xbps_match_pkgdep_in_array(pkgdeps, pkgver))
549 continue;
550
551 xbps_dictionary_get_cstring_nocopy(pkgd,
552 "architecture", &arch);
553 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
554 continue;
555
556 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver);
557 /* match */
558 if (revdeps == NULL)
559 revdeps = xbps_array_create();
560
561 if (!xbps_match_string_in_array(revdeps, tpkgver))
562 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
563 }
564 xbps_object_iterator_release(iter);
565 return revdeps;
566}
567
568xbps_array_t
569xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
570{
571 xbps_array_t revdeps = NULL, vdeps = NULL;
572 xbps_dictionary_t pkgd;
573 const char *vpkg;
574 bool match = false;
575
576 if (repo->idx == NULL)
577 return NULL;
578
579 if (((pkgd = xbps_repo_get_pkg(repo, pkg)) == NULL) &&
580 ((pkgd = xbps_repo_get_virtualpkg(repo, pkg)) == NULL)) {
581 errno = ENOENT;
582 return NULL;
583 }
584 /*
585 * If pkg is a virtual pkg let's match it instead of the real pkgver.
586 */
587 if ((vdeps = xbps_dictionary_get(pkgd, "provides"))) {
588 for (unsigned int i = 0; i < xbps_array_count(vdeps); i++) {
589 char vpkgn[XBPS_NAME_SIZE];
590
591 xbps_array_get_cstring_nocopy(vdeps, i, &vpkg);
592 if (!xbps_pkg_name(vpkgn, XBPS_NAME_SIZE, vpkg)) {
593 abort();
594 }
595 if (strcmp(vpkgn, pkg) == 0) {
596 match = true;
597 break;
598 }
599 vpkg = NULL;
600 }
601 if (match)
602 revdeps = revdeps_match(repo, pkgd, vpkg);
603 }
604 if (!match)
605 revdeps = revdeps_match(repo, pkgd, NULL);
606
607 return revdeps;
608}
609
610int
612{
613 xbps_dictionary_t repokeyd = NULL;
614 xbps_data_t pubkey = NULL;
615 uint16_t pubkey_size = 0;
616 const char *signedby = NULL;
617 char *hexfp = NULL;
618 char *p, *dbkeyd, *rkeyfile = NULL;
619 int import, rv = 0;
620
621 assert(repo);
622 /*
623 * If repository does not have required metadata plist, ignore it.
624 */
625 if (!xbps_dictionary_count(repo->idxmeta)) {
626 xbps_dbg_printf("[repo] `%s' unsigned repository!\n", repo->uri);
627 return 0;
628 }
629 /*
630 * Check for required objects in index-meta:
631 * - signature-by (string)
632 * - public-key (data)
633 * - public-key-size (number)
634 */
635 xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby);
636 xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size);
637 pubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
638
639 if (signedby == NULL || pubkey_size == 0 ||
640 xbps_object_type(pubkey) != XBPS_TYPE_DATA) {
641 xbps_dbg_printf("[repo] `%s': incomplete signed repository "
642 "(missing objs)\n", repo->uri);
643 rv = EINVAL;
644 goto out;
645 }
646 hexfp = xbps_pubkey2fp(pubkey);
647 if (hexfp == NULL) {
648 rv = EINVAL;
649 goto out;
650 }
651 /*
652 * Check if the public key is alredy stored.
653 */
654 rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp);
655 repokeyd = xbps_plist_dictionary_from_file(rkeyfile);
656 if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
657 xbps_dbg_printf("[repo] `%s' public key already stored.\n", repo->uri);
658 goto out;
659 }
660 /*
661 * Notify the client and take appropiate action to import
662 * the repository public key. Pass back the public key openssh fingerprint
663 * to the client.
664 */
665 import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0,
666 hexfp, "`%s' repository has been RSA signed by \"%s\"",
667 repo->uri, signedby);
668 if (import <= 0) {
669 rv = EAGAIN;
670 goto out;
671 }
672
673 p = strdup(rkeyfile);
674 dbkeyd = dirname(p);
675 assert(dbkeyd);
676 if (access(dbkeyd, R_OK|W_OK) == -1) {
677 rv = errno;
678 if (rv == ENOENT)
679 rv = xbps_mkpath(dbkeyd, 0755);
680 if (rv != 0) {
681 rv = errno;
682 xbps_dbg_printf("[repo] `%s' cannot create %s: %s\n",
683 repo->uri, dbkeyd, strerror(errno));
684 free(p);
685 goto out;
686 }
687 }
688 free(p);
689
690 repokeyd = xbps_dictionary_create();
691 xbps_dictionary_set(repokeyd, "public-key", pubkey);
692 xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size);
693 xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby);
694
695 if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) {
696 rv = errno;
697 xbps_dbg_printf("[repo] `%s' failed to externalize %s: %s\n",
698 repo->uri, rkeyfile, strerror(rv));
699 }
700
701out:
702 if (hexfp)
703 free(hexfp);
704 if (repokeyd)
705 xbps_object_release(repokeyd);
706 if (rkeyfile)
707 free(rkeyfile);
708 return rv;
709}
char metadir[XBPS_MAXPATH+sizeof(XBPS_META_PATH)]
Definition xbps.h:664
const char * target_arch
Definition xbps.h:631
xbps_array_t repositories
Definition xbps.h:563
char native_arch[64]
Definition xbps.h:671
int(* state_cb)(const struct xbps_state_cb_data *, void *)
Definition xbps.h:588
int flags
Definition xbps.h:679
Generic XBPS structure handler for initialization.
Definition xbps.h:550
bool xbps_match_pkgdep_in_array(xbps_array_t array, const char *pkgver)
bool xbps_match_string_in_array(xbps_array_t array, const char *val)
xbps_dictionary_t xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:441
struct xbps_repo * xbps_repo_open(struct xbps_handle *xhp, const char *url)
Definition repo.c:340
struct xbps_repo * xbps_repo_stage_open(struct xbps_handle *xhp, const char *url)
Definition repo.c:329
void xbps_repo_release(struct xbps_repo *repo)
Definition repo.c:388
bool xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
Definition repo.c:306
int xbps_repo_key_import(struct xbps_repo *repo)
Definition repo.c:611
struct xbps_repo * xbps_repo_public_open(struct xbps_handle *xhp, const char *url)
Definition repo.c:335
void xbps_repo_close(struct xbps_repo *repo)
Definition repo.c:372
char * xbps_repo_path(struct xbps_handle *xhp, const char *url)
Definition repo.c:51
xbps_dictionary_t xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:407
bool xbps_repo_fetch_remote(struct xbps_repo *repo, const char *url)
bool xbps_repo_lock(struct xbps_handle *xhp, const char *repodir, int *lockfd, char **lockfname)
Definition repo.c:86
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
Definition repo.c:569
void xbps_repo_unlock(int lockfd, char *lockfname)
Definition repo.c:124
char * xbps_repo_path_with_name(struct xbps_handle *xhp, const char *url, const char *name)
Definition repo.c:57
bool xbps_repo_store(struct xbps_handle *xhp, const char *repo)
Definition repo.c:267
bool is_signed
Definition xbps.h:1456
xbps_dictionary_t idxmeta
Definition xbps.h:1434
bool is_remote
Definition xbps.h:1450
struct xbps_handle * xhp
Definition xbps.h:1422
xbps_dictionary_t idx
Definition xbps.h:1428
const char * uri
Definition xbps.h:1440
Repository structure.
Definition xbps.h:1409
xbps_dictionary_t xbps_plist_dictionary_from_file(const char *path)
char * xbps_pubkey2fp(xbps_data_t pubkey)
Definition pubkey2fp.c:66
char * xbps_xasprintf(const char *fmt,...) __attribute__((format(printf
bool xbps_pkg_name(char *dst, size_t len, const char *pkg)
Definition util.c:253
int xbps_mkpath(const char *path, mode_t mode)
Definition mkpath.c:42
bool xbps_remove_string_from_array(xbps_array_t array, const char *str)
bool xbps_repository_is_remote(const char *uri)
Definition util.c:66
bool xbps_pkg_arch_match(struct xbps_handle *xhp, const char *orig, const char *target)
Definition util.c:484