XBPS Library API 20250624
The X Binary Package System
repo.c
1/*-
2 * Copyright (c) 2012-2020 Juan Romero Pardines.
3 * Copyright (c) 2023 Duncan Overbruck <mail@duncano.de>.
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/file.h>
28
29#include <errno.h>
30#include <fcntl.h>
31#include <libgen.h>
32#include <limits.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
36
37#include <archive.h>
38#include <archive_entry.h>
39
40#include "xbps_api_impl.h"
41
42/**
43 * @file lib/repo.c
44 * @brief Repository functions
45 * @defgroup repo Repository functions
46 */
47
48int
49xbps_repo_lock(const char *repodir, const char *arch)
50{
51 char path[PATH_MAX];
52 int fd;
53 int r;
54
55 if (xbps_repository_is_remote(repodir))
56 return -EINVAL;
57
58 r = snprintf(path, sizeof(path), "%s/%s-repodata.lock", repodir, arch);
59 if (r < 0 || (size_t)r > sizeof(path)) {
60 return -ENAMETOOLONG;
61 }
62
63 fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC, 0660);
64 if (fd == -1)
65 return -errno;
66
67 if (flock(fd, LOCK_EX|LOCK_NB) == 0)
68 return fd;
69 if (errno != EWOULDBLOCK) {
70 r = -errno;
71 close(fd);
72 return r;
73 }
74
75 xbps_warn_printf("repository locked: %s: waiting...", repodir);
76 if (flock(fd, LOCK_EX) == -1) {
77 r = -errno;
78 close(fd);
79 return r;
80 }
81
82 return fd;
83}
84
85void
86xbps_repo_unlock(const char *repodir, const char *arch, int fd)
87{
88 char path[PATH_MAX];
89 int r;
90
91 if (fd != -1)
92 close(0);
93
94 r = snprintf(path, sizeof(path), "%s/%s-repodata.lock", repodir, arch);
95 if (r < 0 || (size_t)r > sizeof(path))
96 return;
97 unlink(path);
98}
99
100static int
101repo_read_next(struct xbps_repo *repo, struct archive *ar, struct archive_entry **entry)
102{
103 int r;
104
105 r = archive_read_next_header(ar, entry);
106 if (r == ARCHIVE_FATAL) {
107 xbps_error_printf("failed to read repository: %s: %s\n",
108 repo->uri, archive_error_string(ar));
109 return -xbps_archive_errno(ar);
110 } else if (r == ARCHIVE_WARN) {
111 xbps_warn_printf("reading repository: %s: %s\n",
112 repo->uri, archive_error_string(ar));
113 return 0;
114 } else if (r == ARCHIVE_EOF) {
115 return -EIO;
116 }
117 return 0;
118}
119
120static int
121repo_read_index(struct xbps_repo *repo, struct archive *ar)
122{
123 struct archive_entry *entry;
124 char *buf;
125 int r;
126
127 r = repo_read_next(repo, ar, &entry);
128 if (r < 0)
129 return r;
130
131 /* index.plist */
132 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_INDEX) != 0) {
133 xbps_error_printf("failed to read repository index: %s: unexpected archive entry\n",
134 repo->uri);
135 r = -EINVAL;
136 return r;
137 }
138
139 if (archive_entry_size(entry) == 0) {
140 r = archive_read_data_skip(ar);
141 if (r == ARCHIVE_FATAL) {
142 xbps_error_printf("failed to read repository: %s: archive error: %s\n",
143 repo->uri, archive_error_string(ar));
144 return -xbps_archive_errno(ar);
145 }
146 repo->index = xbps_dictionary_create();
147 return 0;
148 }
149
150 buf = xbps_archive_get_file(ar, entry);
151 if (!buf) {
152 r = -errno;
153 xbps_error_printf(
154 "failed to open repository: %s: failed to read index: %s\n",
155 repo->uri, strerror(-r));
156 return r;
157 }
158 repo->index = xbps_dictionary_internalize(buf);
159 r = -errno;
160 free(buf);
161 if (!repo->index) {
162 if (!r)
163 r = -EINVAL;
164 xbps_error_printf(
165 "failed to open repository: %s: failed to parse index: %s\n",
166 repo->uri, strerror(-r));
167 return r;
168 }
169
170 xbps_dictionary_make_immutable(repo->index);
171 return 0;
172}
173
174static int
175repo_read_meta(struct xbps_repo *repo, struct archive *ar)
176{
177 struct archive_entry *entry;
178 char *buf;
179 int r;
180
181 r = repo_read_next(repo, ar, &entry);
182 if (r < 0)
183 return r;
184
185 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_META) != 0) {
186 xbps_error_printf("failed to read repository metadata: %s: unexpected archive entry\n",
187 repo->uri);
188 r = -EINVAL;
189 return r;
190 }
191 if (archive_entry_size(entry) == 0) {
192 r = archive_read_data_skip(ar);
193 if (r == ARCHIVE_FATAL) {
194 xbps_error_printf("failed to read repository: %s: archive error: %s\n",
195 repo->uri, archive_error_string(ar));
196 return -xbps_archive_errno(ar);
197 }
198 repo->idxmeta = NULL;
199 return 0;
200 }
201
202 buf = xbps_archive_get_file(ar, entry);
203 if (!buf) {
204 r = -errno;
205 xbps_error_printf(
206 "failed to read repository metadata: %s: failed to read "
207 "metadata: %s\n",
208 repo->uri, strerror(-r));
209 return r;
210 }
211 /* for backwards compatibility check if the content is DEADBEEF. */
212 if (strcmp(buf, "DEADBEEF") == 0) {
213 free(buf);
214 return 0;
215 }
216
217 errno = 0;
218 repo->idxmeta = xbps_dictionary_internalize(buf);
219 r = -errno;
220 free(buf);
221 if (!repo->idxmeta) {
222 if (!r)
223 r = -EINVAL;
224 xbps_error_printf(
225 "failed to read repository metadata: %s: failed to parse "
226 "metadata: %s\n",
227 repo->uri, strerror(-r));
228 return r;
229 }
230
231 repo->is_signed = true;
232 xbps_dictionary_make_immutable(repo->idxmeta);
233 return 0;
234}
235
236static int
237repo_read_stage(struct xbps_repo *repo, struct archive *ar)
238{
239 struct archive_entry *entry;
240 int r;
241
242 r = repo_read_next(repo, ar, &entry);
243 if (r < 0) {
244 /* XXX: backwards compatibility missing */
245 if (r == -EIO) {
246 repo->stage = xbps_dictionary_create();
247 return 0;
248 }
249 return r;
250 }
251
252 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_STAGE) != 0) {
253 xbps_error_printf("failed to read repository stage: %s: unexpected archive entry\n",
254 repo->uri);
255 r = -EINVAL;
256 return r;
257 }
258 if (archive_entry_size(entry) == 0) {
259 repo->stage = xbps_dictionary_create();
260 return 0;
261 }
262
263 repo->stage = xbps_archive_get_dictionary(ar, entry);
264 if (!repo->stage) {
265 xbps_error_printf("failed to open repository: %s: reading stage: %s\n",
266 repo->uri, archive_error_string(ar));
267 return -EIO;
268 }
269 xbps_dictionary_make_immutable(repo->stage);
270 return 0;
271}
272
273static int
274repo_read(struct xbps_repo *repo, struct archive *ar)
275{
276 int r;
277
278 r = repo_read_index(repo, ar);
279 if (r < 0)
280 return r;
281 r = repo_read_meta(repo, ar);
282 if (r < 0)
283 return r;
284 r = repo_read_stage(repo, ar);
285 if (r < 0)
286 return r;
287
288 return r;
289}
290
291static int
292repo_open_local(struct xbps_repo *repo, struct archive *ar)
293{
294 char path[PATH_MAX];
295 int r;
296
297 if (repo->is_remote) {
298 char *cachedir;
299 cachedir = xbps_get_remote_repo_string(repo->uri);
300 if (!cachedir) {
301 r = -EINVAL;
302 xbps_error_printf("failed to open repository: %s: invalid repository url\n",
303 repo->uri);
304 goto err;
305 }
306 r = snprintf(path, sizeof(path), "%s/%s/%s-repodata",
307 repo->xhp->metadir, cachedir, repo->arch);
308 free(cachedir);
309 } else {
310 r = snprintf(path, sizeof(path), "%s/%s-repodata", repo->uri, repo->arch);
311 }
312 if (r < 0 || (size_t)r >= sizeof(path)) {
313 r = -ENAMETOOLONG;
314 xbps_error_printf("failed to open repository: %s: repository path too long\n",
315 repo->uri);
316 goto err;
317 }
318
319 r = xbps_archive_read_open(ar, path);
320 if (r < 0) {
321 if (r != -ENOENT) {
322 xbps_error_printf("failed to open repodata: %s: %s\n",
323 path, strerror(-r));
324 }
325 goto err;
326 }
327
328 return 0;
329err:
330 return r;
331}
332
333static int
334repo_open_remote(struct xbps_repo *repo, struct archive *ar)
335{
336 char url[PATH_MAX];
337 int r;
338
339 r = snprintf(url, sizeof(url), "%s/%s-repodata", repo->uri, repo->arch);
340 if (r < 0 || (size_t)r >= sizeof(url)) {
341 xbps_error_printf("failed to open repository: %s: repository url too long\n",
342 repo->uri);
343 return -ENAMETOOLONG;
344 }
345
346 r = xbps_archive_read_open_remote(ar, url);
347 if (r < 0) {
348 xbps_error_printf("failed to open repository: %s: %s\n", repo->uri, strerror(-r));
349 return r;
350 }
351
352 return 0;
353}
354
355static int
356repo_open(struct xbps_handle *xhp, struct xbps_repo *repo)
357{
358 struct archive *ar;
359 int r;
360
361 ar = xbps_archive_read_new();
362 if (!ar) {
363 r = -errno;
364 xbps_error_printf("failed to open repo: %s\n", strerror(-r));
365 return r;
366 }
367
368 if (repo->is_remote && (xhp->flags & XBPS_FLAG_REPOS_MEMSYNC))
369 r = repo_open_remote(repo, ar);
370 else
371 r = repo_open_local(repo, ar);
372 if (r < 0)
373 goto err;
374
375 r = repo_read(repo, ar);
376 if (r < 0)
377 goto err;
378
379 r = archive_read_close(ar);
380 if (r < 0) {
381 xbps_error_printf("failed to open repository: %s: closing archive: %s\n",
382 repo->uri, archive_error_string(ar));
383 goto err;
384 }
385
386 archive_read_free(ar);
387 return 0;
388err:
389 archive_read_free(ar);
390 return r;
391}
392
393bool
394xbps_repo_store(struct xbps_handle *xhp, const char *repo)
395{
396 char *url = NULL;
397
398 assert(xhp);
399 assert(repo);
400
401 if (xhp->repositories == NULL) {
402 xhp->repositories = xbps_array_create();
403 assert(xhp->repositories);
404 }
405 /*
406 * If it's a local repo and path is relative, make it absolute.
407 */
408 if (!xbps_repository_is_remote(repo)) {
409 if (repo[0] != '/' && repo[0] != '\0') {
410 if ((url = realpath(repo, NULL)) == NULL)
411 xbps_dbg_printf("[repo] %s: realpath %s\n", __func__, repo);
412 }
413 }
414 if (xbps_match_string_in_array(xhp->repositories, url ? url : repo)) {
415 xbps_dbg_printf("[repo] `%s' already stored\n", url ? url : repo);
416 if (url)
417 free(url);
418 return false;
419 }
420 if (xbps_array_add_cstring(xhp->repositories, url ? url : repo)) {
421 xbps_dbg_printf("[repo] `%s' stored successfully\n", url ? url : repo);
422 if (url)
423 free(url);
424 return true;
425 }
426 if (url)
427 free(url);
428
429 return false;
430}
431
432bool
433xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
434{
435 char *url;
436 bool rv = false;
437
438 assert(xhp);
439 assert(repo);
440
441 if (xhp->repositories == NULL)
442 return false;
443
444 url = strdup(repo);
446 if (url)
447 xbps_dbg_printf("[repo] `%s' removed\n", url);
448 rv = true;
449 }
450 free(url);
451
452 return rv;
453}
454
455static int
456repo_merge_stage(struct xbps_repo *repo)
457{
458 xbps_dictionary_t idx;
459 xbps_object_t keysym;
460 xbps_object_iterator_t iter;
461 int r = 0;
462
463 idx = xbps_dictionary_copy_mutable(repo->index);
464 if (!idx)
465 return -errno;
466
467 iter = xbps_dictionary_iterator(repo->stage);
468 if (!iter) {
469 r = -errno;
470 goto err1;
471 }
472
473 while ((keysym = xbps_object_iterator_next(iter))) {
474 const char *pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym);
475 xbps_dictionary_t pkgd = xbps_dictionary_get_keysym(repo->stage, keysym);
476 if (!xbps_dictionary_set(idx, pkgname, pkgd)) {
477 r = -errno;
478 goto err2;
479 }
480 }
481
482 xbps_object_iterator_release(iter);
483 repo->idx = idx;
484 return 0;
485err2:
486 xbps_object_iterator_release(iter);
487err1:
488 xbps_object_release(idx);
489 return r;
490}
491
492struct xbps_repo *
493xbps_repo_open(struct xbps_handle *xhp, const char *url)
494{
495 struct xbps_repo *repo;
496 int r;
497
498 repo = calloc(1, sizeof(*repo));
499 if (!repo) {
500 r = -errno;
501 xbps_error_printf("failed to open repository: %s\n", strerror(-r));
502 errno = -r;
503 return NULL;
504 }
505 repo->xhp = xhp;
506 repo->uri = url;
509
510 r = repo_open(xhp, repo);
511 if (r < 0) {
512 free(repo);
513 errno = -r;
514 return NULL;
515 }
516
517 if (xbps_dictionary_count(repo->stage) == 0 ||
518 (repo->is_remote && !(xhp->flags & XBPS_FLAG_USE_STAGE))) {
519 repo->idx = repo->index;
520 xbps_object_retain(repo->idx);
521 return repo;
522 }
523
524 r = repo_merge_stage(repo);
525 if (r < 0) {
526 xbps_error_printf(
527 "failed to open repository: %s: could not merge stage: %s\n",
528 url, strerror(-r));
529 xbps_repo_release(repo);
530 errno = -r;
531 return NULL;
532 }
533
534 return repo;
535}
536
537
538void
540{
541 if (!repo)
542 return;
543
544 if (repo->idx) {
545 xbps_object_release(repo->idx);
546 repo->idx = NULL;
547 }
548 if (repo->index) {
549 xbps_object_release(repo->index);
550 repo->idx = NULL;
551 }
552 if (repo->stage) {
553 xbps_object_release(repo->stage);
554 repo->idx = NULL;
555 }
556 if (repo->idxmeta) {
557 xbps_object_release(repo->idxmeta);
558 repo->idxmeta = NULL;
559 }
560 free(repo);
561}
562
563xbps_dictionary_t
564xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
565{
566 xbps_dictionary_t pkgd;
567 const char *pkgver;
568 char pkgname[XBPS_NAME_SIZE] = {0};
569
570 if (!repo || !repo->idx || !pkg) {
571 return NULL;
572 }
573 pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
574 if (!pkgd) {
575 return NULL;
576 }
577 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
578 return pkgd;
579 }
580 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
581 return NULL;
582 }
583 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
584 return NULL;
585 }
586 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
587 return NULL;
588 }
589 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
590 return NULL;
591 }
592 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
593
594 return pkgd;
595}
596
597xbps_dictionary_t
598xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
599{
600 xbps_dictionary_t pkgd = NULL;
601 const char *pkgver;
602 char pkgname[XBPS_NAME_SIZE] = {0};
603
604 if (!repo || !repo->idx || !pkg) {
605 return NULL;
606 }
607 /* Try matching vpkg from configuration files */
608 if ((pkgd = xbps_find_virtualpkg_in_conf(repo->xhp, repo->idx, pkg))) {
609 goto add;
610 }
611 /* ... otherwise match a real pkg */
612 if ((pkgd = xbps_find_pkg_in_dict(repo->idx, pkg))) {
613 goto add;
614 }
615 return NULL;
616add:
617 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
618 return pkgd;
619 }
620 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
621 return NULL;
622 }
623 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
624 return NULL;
625 }
626 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
627 return NULL;
628 }
629 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
630 return NULL;
631 }
632 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
633 return pkgd;
634}
635
636static xbps_array_t
637revdeps_match(struct xbps_repo *repo, xbps_dictionary_t tpkgd, const char *str)
638{
639 xbps_dictionary_t pkgd;
640 xbps_array_t revdeps = NULL, pkgdeps, provides;
641 xbps_object_iterator_t iter;
642 xbps_object_t obj;
643 const char *pkgver = NULL, *tpkgver = NULL, *arch = NULL, *vpkg = NULL;
644
645 iter = xbps_dictionary_iterator(repo->idx);
646 assert(iter);
647
648 while ((obj = xbps_object_iterator_next(iter))) {
649 pkgd = xbps_dictionary_get_keysym(repo->idx, obj);
650 if (xbps_dictionary_equals(pkgd, tpkgd))
651 continue;
652
653 pkgdeps = xbps_dictionary_get(pkgd, "run_depends");
654 if (!xbps_array_count(pkgdeps))
655 continue;
656 /*
657 * Try to match passed in string.
658 */
659 if (str) {
660 if (!xbps_match_pkgdep_in_array(pkgdeps, str))
661 continue;
662 xbps_dictionary_get_cstring_nocopy(pkgd,
663 "architecture", &arch);
664 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
665 continue;
666
667 xbps_dictionary_get_cstring_nocopy(pkgd,
668 "pkgver", &tpkgver);
669 /* match */
670 if (revdeps == NULL)
671 revdeps = xbps_array_create();
672
673 if (!xbps_match_string_in_array(revdeps, tpkgver))
674 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
675
676 continue;
677 }
678 /*
679 * Try to match any virtual package.
680 */
681 provides = xbps_dictionary_get(tpkgd, "provides");
682 for (unsigned int i = 0; i < xbps_array_count(provides); i++) {
683 xbps_array_get_cstring_nocopy(provides, i, &vpkg);
684 if (!xbps_match_pkgdep_in_array(pkgdeps, vpkg))
685 continue;
686
687 xbps_dictionary_get_cstring_nocopy(pkgd,
688 "architecture", &arch);
689 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
690 continue;
691
692 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver",
693 &tpkgver);
694 /* match */
695 if (revdeps == NULL)
696 revdeps = xbps_array_create();
697
698 if (!xbps_match_string_in_array(revdeps, tpkgver))
699 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
700 }
701 /*
702 * Try to match by pkgver.
703 */
704 xbps_dictionary_get_cstring_nocopy(tpkgd, "pkgver", &pkgver);
705 if (!xbps_match_pkgdep_in_array(pkgdeps, pkgver))
706 continue;
707
708 xbps_dictionary_get_cstring_nocopy(pkgd,
709 "architecture", &arch);
710 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
711 continue;
712
713 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver);
714 /* match */
715 if (revdeps == NULL)
716 revdeps = xbps_array_create();
717
718 if (!xbps_match_string_in_array(revdeps, tpkgver))
719 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
720 }
721 xbps_object_iterator_release(iter);
722 return revdeps;
723}
724
725xbps_array_t
726xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
727{
728 xbps_array_t revdeps = NULL, vdeps = NULL;
729 xbps_dictionary_t pkgd;
730 const char *vpkg;
731 bool match = false;
732
733 if (repo->idx == NULL)
734 return NULL;
735
736 if (((pkgd = xbps_repo_get_pkg(repo, pkg)) == NULL) &&
737 ((pkgd = xbps_repo_get_virtualpkg(repo, pkg)) == NULL)) {
738 errno = ENOENT;
739 return NULL;
740 }
741 /*
742 * If pkg is a virtual pkg let's match it instead of the real pkgver.
743 */
744 if ((vdeps = xbps_dictionary_get(pkgd, "provides"))) {
745 for (unsigned int i = 0; i < xbps_array_count(vdeps); i++) {
746 char vpkgn[XBPS_NAME_SIZE];
747
748 xbps_array_get_cstring_nocopy(vdeps, i, &vpkg);
749 if (!xbps_pkg_name(vpkgn, XBPS_NAME_SIZE, vpkg)) {
750 abort();
751 }
752 if (strcmp(vpkgn, pkg) == 0) {
753 match = true;
754 break;
755 }
756 vpkg = NULL;
757 }
758 if (match)
759 revdeps = revdeps_match(repo, pkgd, vpkg);
760 }
761 if (!match)
762 revdeps = revdeps_match(repo, pkgd, NULL);
763
764 return revdeps;
765}
766
767int
769{
770 xbps_dictionary_t repokeyd = NULL;
771 xbps_data_t pubkey = NULL;
772 uint16_t pubkey_size = 0;
773 const char *signedby = NULL;
774 char *hexfp = NULL;
775 char *p, *dbkeyd, *rkeyfile = NULL;
776 int import, rv = 0;
777
778 assert(repo);
779 /*
780 * If repository does not have required metadata plist, ignore it.
781 */
782 if (!xbps_dictionary_count(repo->idxmeta)) {
783 xbps_dbg_printf("[repo] `%s' unsigned repository!\n", repo->uri);
784 return 0;
785 }
786 /*
787 * Check for required objects in index-meta:
788 * - signature-by (string)
789 * - public-key (data)
790 * - public-key-size (number)
791 */
792 xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby);
793 xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size);
794 pubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
795
796 if (signedby == NULL || pubkey_size == 0 ||
797 xbps_object_type(pubkey) != XBPS_TYPE_DATA) {
798 xbps_dbg_printf("[repo] `%s': incomplete signed repository "
799 "(missing objs)\n", repo->uri);
800 rv = EINVAL;
801 goto out;
802 }
803 hexfp = xbps_pubkey2fp(pubkey);
804 if (hexfp == NULL) {
805 rv = EINVAL;
806 goto out;
807 }
808 /*
809 * Check if the public key is alredy stored.
810 */
811 rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp);
812 repokeyd = xbps_plist_dictionary_from_file(rkeyfile);
813 if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
814 xbps_dbg_printf("[repo] `%s' public key already stored.\n", repo->uri);
815 goto out;
816 }
817 /*
818 * Notify the client and take appropiate action to import
819 * the repository public key. Pass back the public key openssh fingerprint
820 * to the client.
821 */
822 import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0,
823 hexfp, "`%s' repository has been RSA signed by \"%s\"",
824 repo->uri, signedby);
825 if (import <= 0) {
826 rv = EAGAIN;
827 goto out;
828 }
829
830 p = strdup(rkeyfile);
831 dbkeyd = dirname(p);
832 assert(dbkeyd);
833 if (access(dbkeyd, R_OK|W_OK) == -1) {
834 rv = errno;
835 if (rv == ENOENT)
836 rv = xbps_mkpath(dbkeyd, 0755);
837 if (rv != 0) {
838 rv = errno;
839 xbps_dbg_printf("[repo] `%s' cannot create %s: %s\n",
840 repo->uri, dbkeyd, strerror(errno));
841 free(p);
842 goto out;
843 }
844 }
845 free(p);
846
847 repokeyd = xbps_dictionary_create();
848 xbps_dictionary_set(repokeyd, "public-key", pubkey);
849 xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size);
850 xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby);
851
852 if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) {
853 rv = errno;
854 xbps_dbg_printf("[repo] `%s' failed to externalize %s: %s\n",
855 repo->uri, rkeyfile, strerror(rv));
856 }
857
858out:
859 if (hexfp)
860 free(hexfp);
861 if (repokeyd)
862 xbps_object_release(repokeyd);
863 if (rkeyfile)
864 free(rkeyfile);
865 return rv;
866}
xbps_array_t repositories
Definition xbps.h:572
const char * target_arch
Definition xbps.h:640
int flags
Definition xbps.h:688
char metadir[XBPS_MAXPATH]
Definition xbps.h:673
char native_arch[64]
Definition xbps.h:680
Generic XBPS structure handler for initialization.
Definition xbps.h:559
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:598
struct xbps_repo * xbps_repo_open(struct xbps_handle *xhp, const char *url)
Definition repo.c:493
void xbps_repo_release(struct xbps_repo *repo)
Definition repo.c:539
int xbps_repo_lock(const char *repodir, const char *arch)
Definition repo.c:49
bool xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
Definition repo.c:433
int xbps_repo_key_import(struct xbps_repo *repo)
Definition repo.c:768
xbps_dictionary_t xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:564
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
Definition repo.c:726
void xbps_repo_unlock(const char *repodir, const char *arch, int fd)
Definition repo.c:86
bool xbps_repo_store(struct xbps_handle *xhp, const char *repo)
Definition repo.c:394
bool is_signed
Definition xbps.h:1480
xbps_dictionary_t idxmeta
Definition xbps.h:1462
bool is_remote
Definition xbps.h:1474
struct xbps_handle * xhp
Definition xbps.h:1432
xbps_dictionary_t index
Definition xbps.h:1450
const char * uri
Definition xbps.h:1468
xbps_dictionary_t idx
Definition xbps.h:1444
const char * arch
Definition xbps.h:1438
Repository structure.
Definition xbps.h:1420
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