XBPS Library API 20250531
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 -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
120
121static int
122repo_read_index(struct xbps_repo *repo, struct archive *ar)
123{
124 struct archive_entry *entry;
125 char *buf;
126 int r;
127
128 r = repo_read_next(repo, ar, &entry);
129 if (r < 0)
130 return r;
131
132 /* index.plist */
133 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_INDEX) != 0) {
134 xbps_error_printf("failed to read repository index: %s: unexpected archive entry\n",
135 repo->uri);
136 r = -EINVAL;
137 return r;
138 }
139
140 if (archive_entry_size(entry) == 0) {
141 r = archive_read_data_skip(ar);
142 if (r == ARCHIVE_FATAL) {
143 xbps_error_printf("failed to read repository: %s: archive error: %s\n",
144 repo->uri, archive_error_string(ar));
145 return -archive_errno(ar);
146 }
147 repo->index = xbps_dictionary_create();
148 return 0;
149 }
150
151 buf = xbps_archive_get_file(ar, entry);
152 if (!buf)
153 return -errno;
154 repo->index = xbps_dictionary_internalize(buf);
155 r = -errno;
156 free(buf);
157 if (!repo->index) {
158 xbps_error_printf("failed to open repository: %s: reading index: %s\n",
159 repo->uri, strerror(-r));
160 return -EIO;
161 }
162
163 xbps_dictionary_make_immutable(repo->index);
164 return 0;
165}
166
167static int
168repo_read_meta(struct xbps_repo *repo, struct archive *ar)
169{
170 struct archive_entry *entry;
171 char *buf;
172 int r;
173
174 r = repo_read_next(repo, ar, &entry);
175 if (r < 0)
176 return r;
177
178 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_META) != 0) {
179 xbps_error_printf("failed to read repository metadata: %s: unexpected archive entry\n",
180 repo->uri);
181 r = -EINVAL;
182 return r;
183 }
184 if (archive_entry_size(entry) == 0) {
185 r = archive_read_data_skip(ar);
186 if (r == ARCHIVE_FATAL) {
187 xbps_error_printf("failed to read repository: %s: archive error: %s\n",
188 repo->uri, archive_error_string(ar));
189 return -archive_errno(ar);
190 }
191 repo->idxmeta = xbps_dictionary_create();
192 return 0;
193 }
194
195 buf = xbps_archive_get_file(ar, entry);
196 if (!buf) {
197 r = -errno;
198 xbps_error_printf("failed to read repository metadata: %s: %s\n",
199 repo->uri, strerror(-r));
200 return r;
201 }
202 /* for backwards compatibility check if the content is DEADBEEF. */
203 if (strcmp(buf, "DEADBEEF") == 0) {
204 free(buf);
205 return 0;
206 }
207
208 errno = 0;
209 repo->idxmeta = xbps_dictionary_internalize(buf);
210 r = -errno;
211
212 free(buf);
213
214 if (!repo->idxmeta) {
215 if (!r) {
216 xbps_error_printf("failed to read repository metadata: %s: invalid dictionary\n",
217 repo->uri);
218 return -EINVAL;
219 }
220 xbps_error_printf("failed to read repository metadata: %s: %s\n",
221 repo->uri, strerror(-r));
222 return r;
223 }
224
225 xbps_dictionary_make_immutable(repo->idxmeta);
226 return 0;
227}
228
229static int
230repo_read_stage(struct xbps_repo *repo, struct archive *ar)
231{
232 struct archive_entry *entry;
233 int r;
234
235 r = repo_read_next(repo, ar, &entry);
236 if (r < 0) {
237 /* XXX: backwards compatibility missing */
238 if (r == -EIO) {
239 repo->stage = xbps_dictionary_create();
240 return 0;
241 }
242 return r;
243 }
244
245 if (strcmp(archive_entry_pathname(entry), XBPS_REPODATA_STAGE) != 0) {
246 xbps_error_printf("failed to read repository stage: %s: unexpected archive entry\n",
247 repo->uri);
248 r = -EINVAL;
249 return r;
250 }
251 if (archive_entry_size(entry) == 0) {
252 repo->stage = xbps_dictionary_create();
253 return 0;
254 }
255
256 repo->stage = xbps_archive_get_dictionary(ar, entry);
257 if (!repo->stage) {
258 xbps_error_printf("failed to open repository: %s: reading stage: %s\n",
259 repo->uri, archive_error_string(ar));
260 return -EIO;
261 }
262 xbps_dictionary_make_immutable(repo->stage);
263 return 0;
264}
265
266static int
267repo_read(struct xbps_repo *repo, struct archive *ar)
268{
269 int r;
270
271 r = repo_read_index(repo, ar);
272 if (r < 0)
273 return r;
274 r = repo_read_meta(repo, ar);
275 if (r < 0)
276 return r;
277 r = repo_read_stage(repo, ar);
278 if (r < 0)
279 return r;
280
281 return r;
282}
283
284static int
285repo_open_local(struct xbps_repo *repo, struct archive *ar)
286{
287 char path[PATH_MAX];
288 int r;
289
290 if (repo->is_remote) {
291 char *cachedir;
292 cachedir = xbps_get_remote_repo_string(repo->uri);
293 if (!cachedir) {
294 r = -EINVAL;
295 xbps_error_printf("failed to open repository: %s: invalid repository url\n",
296 repo->uri);
297 goto err;
298 }
299 r = snprintf(path, sizeof(path), "%s/%s/%s-repodata",
300 repo->xhp->metadir, cachedir, repo->arch);
301 free(cachedir);
302 } else {
303 r = snprintf(path, sizeof(path), "%s/%s-repodata", repo->uri, repo->arch);
304 }
305 if (r < 0 || (size_t)r >= sizeof(path)) {
306 r = -ENAMETOOLONG;
307 xbps_error_printf("failed to open repository: %s: repository path too long\n",
308 repo->uri);
309 goto err;
310 }
311
312 r = xbps_archive_read_open(ar, path);
313 if (r < 0) {
314 if (r != -ENOENT) {
315 xbps_error_printf("failed to open repodata: %s: %s\n",
316 path, strerror(-r));
317 }
318 goto err;
319 }
320
321 return 0;
322err:
323 return r;
324}
325
326static int
327repo_open_remote(struct xbps_repo *repo, struct archive *ar)
328{
329 char url[PATH_MAX];
330 int r;
331
332 r = snprintf(url, sizeof(url), "%s/%s-repodata", repo->uri, repo->arch);
333 if (r < 0 || (size_t)r >= sizeof(url)) {
334 xbps_error_printf("failed to open repository: %s: repository url too long\n",
335 repo->uri);
336 return -ENAMETOOLONG;
337 }
338
339 r = xbps_archive_read_open_remote(ar, url);
340 if (r < 0) {
341 xbps_error_printf("failed to open repository: %s: %s\n", repo->uri, strerror(-r));
342 archive_read_free(ar);
343 return r;
344 }
345
346 return 0;
347}
348
349static int
350repo_open(struct xbps_handle *xhp, struct xbps_repo *repo)
351{
352 struct archive *ar;
353 int r;
354
355 ar = xbps_archive_read_new();
356 if (!ar) {
357 r = -errno;
358 xbps_error_printf("failed to open repo: %s\n", strerror(-r));
359 return r;
360 }
361
362 if (repo->is_remote && (xhp->flags & XBPS_FLAG_REPOS_MEMSYNC))
363 r = repo_open_remote(repo, ar);
364 else
365 r = repo_open_local(repo, ar);
366 if (r < 0)
367 goto err;
368
369 r = repo_read(repo, ar);
370 if (r < 0)
371 goto err;
372
373 r = archive_read_close(ar);
374 if (r < 0) {
375 xbps_error_printf("failed to open repository: %s: closing archive: %s\n",
376 repo->uri, archive_error_string(ar));
377 goto err;
378 }
379
380 archive_read_free(ar);
381 return 0;
382err:
383 archive_read_free(ar);
384 return r;
385}
386
387bool
388xbps_repo_store(struct xbps_handle *xhp, const char *repo)
389{
390 char *url = NULL;
391
392 assert(xhp);
393 assert(repo);
394
395 if (xhp->repositories == NULL) {
396 xhp->repositories = xbps_array_create();
397 assert(xhp->repositories);
398 }
399 /*
400 * If it's a local repo and path is relative, make it absolute.
401 */
402 if (!xbps_repository_is_remote(repo)) {
403 if (repo[0] != '/' && repo[0] != '\0') {
404 if ((url = realpath(repo, NULL)) == NULL)
405 xbps_dbg_printf("[repo] %s: realpath %s\n", __func__, repo);
406 }
407 }
408 if (xbps_match_string_in_array(xhp->repositories, url ? url : repo)) {
409 xbps_dbg_printf("[repo] `%s' already stored\n", url ? url : repo);
410 if (url)
411 free(url);
412 return false;
413 }
414 if (xbps_array_add_cstring(xhp->repositories, url ? url : repo)) {
415 xbps_dbg_printf("[repo] `%s' stored successfully\n", url ? url : repo);
416 if (url)
417 free(url);
418 return true;
419 }
420 if (url)
421 free(url);
422
423 return false;
424}
425
426bool
427xbps_repo_remove(struct xbps_handle *xhp, const char *repo)
428{
429 char *url;
430 bool rv = false;
431
432 assert(xhp);
433 assert(repo);
434
435 if (xhp->repositories == NULL)
436 return false;
437
438 url = strdup(repo);
440 if (url)
441 xbps_dbg_printf("[repo] `%s' removed\n", url);
442 rv = true;
443 }
444 free(url);
445
446 return rv;
447}
448
449static int
450repo_merge_stage(struct xbps_repo *repo)
451{
452 xbps_dictionary_t idx;
453 xbps_object_t keysym;
454 xbps_object_iterator_t iter;
455 int r = 0;
456
457 idx = xbps_dictionary_copy_mutable(repo->index);
458 if (!idx)
459 return -errno;
460
461 iter = xbps_dictionary_iterator(repo->stage);
462 if (!iter) {
463 r = -errno;
464 goto err1;
465 }
466
467 while ((keysym = xbps_object_iterator_next(iter))) {
468 const char *pkgname = xbps_dictionary_keysym_cstring_nocopy(keysym);
469 xbps_dictionary_t pkgd = xbps_dictionary_get_keysym(repo->stage, keysym);
470 if (!xbps_dictionary_set(idx, pkgname, pkgd)) {
471 r = -errno;
472 goto err2;
473 }
474 }
475
476 xbps_object_iterator_release(iter);
477 repo->idx = idx;
478 return 0;
479err2:
480 xbps_object_iterator_release(iter);
481err1:
482 xbps_object_release(idx);
483 return r;
484}
485
486struct xbps_repo *
487xbps_repo_open(struct xbps_handle *xhp, const char *url)
488{
489 struct xbps_repo *repo;
490 int r;
491
492 repo = calloc(1, sizeof(*repo));
493 if (!repo) {
494 r = -errno;
495 xbps_error_printf("failed to open repository: %s\n", strerror(-r));
496 errno = -r;
497 return NULL;
498 }
499 repo->xhp = xhp;
500 repo->uri = url;
503
504 r = repo_open(xhp, repo);
505 if (r < 0) {
506 free(repo);
507 errno = -r;
508 return NULL;
509 }
510
511 if (xbps_dictionary_count(repo->stage) == 0 ||
512 (repo->is_remote && !(xhp->flags & XBPS_FLAG_USE_STAGE))) {
513 repo->idx = repo->index;
514 xbps_object_retain(repo->idx);
515 return repo;
516 }
517
518 r = repo_merge_stage(repo);
519 if (r < 0) {
520 xbps_error_printf(
521 "failed to open repository: %s: could not merge stage: %s\n",
522 url, strerror(-r));
523 xbps_repo_release(repo);
524 errno = -r;
525 return NULL;
526 }
527
528 return repo;
529}
530
531
532void
534{
535 if (!repo)
536 return;
537
538 if (repo->idx) {
539 xbps_object_release(repo->idx);
540 repo->idx = NULL;
541 }
542 if (repo->index) {
543 xbps_object_release(repo->index);
544 repo->idx = NULL;
545 }
546 if (repo->stage) {
547 xbps_object_release(repo->stage);
548 repo->idx = NULL;
549 }
550 if (repo->idxmeta) {
551 xbps_object_release(repo->idxmeta);
552 repo->idxmeta = NULL;
553 }
554 free(repo);
555}
556
557xbps_dictionary_t
558xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
559{
560 xbps_dictionary_t pkgd;
561 const char *pkgver;
562 char pkgname[XBPS_NAME_SIZE] = {0};
563
564 if (!repo || !repo->idx || !pkg) {
565 return NULL;
566 }
567 pkgd = xbps_find_virtualpkg_in_dict(repo->xhp, repo->idx, pkg);
568 if (!pkgd) {
569 return NULL;
570 }
571 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
572 return pkgd;
573 }
574 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
575 return NULL;
576 }
577 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
578 return NULL;
579 }
580 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
581 return NULL;
582 }
583 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
584 return NULL;
585 }
586 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
587
588 return pkgd;
589}
590
591xbps_dictionary_t
592xbps_repo_get_pkg(struct xbps_repo *repo, const char *pkg)
593{
594 xbps_dictionary_t pkgd = NULL;
595 const char *pkgver;
596 char pkgname[XBPS_NAME_SIZE] = {0};
597
598 if (!repo || !repo->idx || !pkg) {
599 return NULL;
600 }
601 /* Try matching vpkg from configuration files */
602 if ((pkgd = xbps_find_virtualpkg_in_conf(repo->xhp, repo->idx, pkg))) {
603 goto add;
604 }
605 /* ... otherwise match a real pkg */
606 if ((pkgd = xbps_find_pkg_in_dict(repo->idx, pkg))) {
607 goto add;
608 }
609 return NULL;
610add:
611 if (xbps_dictionary_get(pkgd, "repository") && xbps_dictionary_get(pkgd, "pkgname")) {
612 return pkgd;
613 }
614 if (!xbps_dictionary_set_cstring_nocopy(pkgd, "repository", repo->uri)) {
615 return NULL;
616 }
617 if (!xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver)) {
618 return NULL;
619 }
620 if (!xbps_pkg_name(pkgname, sizeof(pkgname), pkgver)) {
621 return NULL;
622 }
623 if (!xbps_dictionary_set_cstring(pkgd, "pkgname", pkgname)) {
624 return NULL;
625 }
626 xbps_dbg_printf("%s: found %s\n", __func__, pkgver);
627 return pkgd;
628}
629
630static xbps_array_t
631revdeps_match(struct xbps_repo *repo, xbps_dictionary_t tpkgd, const char *str)
632{
633 xbps_dictionary_t pkgd;
634 xbps_array_t revdeps = NULL, pkgdeps, provides;
635 xbps_object_iterator_t iter;
636 xbps_object_t obj;
637 const char *pkgver = NULL, *tpkgver = NULL, *arch = NULL, *vpkg = NULL;
638
639 iter = xbps_dictionary_iterator(repo->idx);
640 assert(iter);
641
642 while ((obj = xbps_object_iterator_next(iter))) {
643 pkgd = xbps_dictionary_get_keysym(repo->idx, obj);
644 if (xbps_dictionary_equals(pkgd, tpkgd))
645 continue;
646
647 pkgdeps = xbps_dictionary_get(pkgd, "run_depends");
648 if (!xbps_array_count(pkgdeps))
649 continue;
650 /*
651 * Try to match passed in string.
652 */
653 if (str) {
654 if (!xbps_match_pkgdep_in_array(pkgdeps, str))
655 continue;
656 xbps_dictionary_get_cstring_nocopy(pkgd,
657 "architecture", &arch);
658 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
659 continue;
660
661 xbps_dictionary_get_cstring_nocopy(pkgd,
662 "pkgver", &tpkgver);
663 /* match */
664 if (revdeps == NULL)
665 revdeps = xbps_array_create();
666
667 if (!xbps_match_string_in_array(revdeps, tpkgver))
668 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
669
670 continue;
671 }
672 /*
673 * Try to match any virtual package.
674 */
675 provides = xbps_dictionary_get(tpkgd, "provides");
676 for (unsigned int i = 0; i < xbps_array_count(provides); i++) {
677 xbps_array_get_cstring_nocopy(provides, i, &vpkg);
678 if (!xbps_match_pkgdep_in_array(pkgdeps, vpkg))
679 continue;
680
681 xbps_dictionary_get_cstring_nocopy(pkgd,
682 "architecture", &arch);
683 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
684 continue;
685
686 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver",
687 &tpkgver);
688 /* match */
689 if (revdeps == NULL)
690 revdeps = xbps_array_create();
691
692 if (!xbps_match_string_in_array(revdeps, tpkgver))
693 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
694 }
695 /*
696 * Try to match by pkgver.
697 */
698 xbps_dictionary_get_cstring_nocopy(tpkgd, "pkgver", &pkgver);
699 if (!xbps_match_pkgdep_in_array(pkgdeps, pkgver))
700 continue;
701
702 xbps_dictionary_get_cstring_nocopy(pkgd,
703 "architecture", &arch);
704 if (!xbps_pkg_arch_match(repo->xhp, arch, NULL))
705 continue;
706
707 xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &tpkgver);
708 /* match */
709 if (revdeps == NULL)
710 revdeps = xbps_array_create();
711
712 if (!xbps_match_string_in_array(revdeps, tpkgver))
713 xbps_array_add_cstring_nocopy(revdeps, tpkgver);
714 }
715 xbps_object_iterator_release(iter);
716 return revdeps;
717}
718
719xbps_array_t
720xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
721{
722 xbps_array_t revdeps = NULL, vdeps = NULL;
723 xbps_dictionary_t pkgd;
724 const char *vpkg;
725 bool match = false;
726
727 if (repo->idx == NULL)
728 return NULL;
729
730 if (((pkgd = xbps_repo_get_pkg(repo, pkg)) == NULL) &&
731 ((pkgd = xbps_repo_get_virtualpkg(repo, pkg)) == NULL)) {
732 errno = ENOENT;
733 return NULL;
734 }
735 /*
736 * If pkg is a virtual pkg let's match it instead of the real pkgver.
737 */
738 if ((vdeps = xbps_dictionary_get(pkgd, "provides"))) {
739 for (unsigned int i = 0; i < xbps_array_count(vdeps); i++) {
740 char vpkgn[XBPS_NAME_SIZE];
741
742 xbps_array_get_cstring_nocopy(vdeps, i, &vpkg);
743 if (!xbps_pkg_name(vpkgn, XBPS_NAME_SIZE, vpkg)) {
744 abort();
745 }
746 if (strcmp(vpkgn, pkg) == 0) {
747 match = true;
748 break;
749 }
750 vpkg = NULL;
751 }
752 if (match)
753 revdeps = revdeps_match(repo, pkgd, vpkg);
754 }
755 if (!match)
756 revdeps = revdeps_match(repo, pkgd, NULL);
757
758 return revdeps;
759}
760
761int
763{
764 xbps_dictionary_t repokeyd = NULL;
765 xbps_data_t pubkey = NULL;
766 uint16_t pubkey_size = 0;
767 const char *signedby = NULL;
768 char *hexfp = NULL;
769 char *p, *dbkeyd, *rkeyfile = NULL;
770 int import, rv = 0;
771
772 assert(repo);
773 /*
774 * If repository does not have required metadata plist, ignore it.
775 */
776 if (!xbps_dictionary_count(repo->idxmeta)) {
777 xbps_dbg_printf("[repo] `%s' unsigned repository!\n", repo->uri);
778 return 0;
779 }
780 /*
781 * Check for required objects in index-meta:
782 * - signature-by (string)
783 * - public-key (data)
784 * - public-key-size (number)
785 */
786 xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &signedby);
787 xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &pubkey_size);
788 pubkey = xbps_dictionary_get(repo->idxmeta, "public-key");
789
790 if (signedby == NULL || pubkey_size == 0 ||
791 xbps_object_type(pubkey) != XBPS_TYPE_DATA) {
792 xbps_dbg_printf("[repo] `%s': incomplete signed repository "
793 "(missing objs)\n", repo->uri);
794 rv = EINVAL;
795 goto out;
796 }
797 hexfp = xbps_pubkey2fp(pubkey);
798 if (hexfp == NULL) {
799 rv = EINVAL;
800 goto out;
801 }
802 /*
803 * Check if the public key is alredy stored.
804 */
805 rkeyfile = xbps_xasprintf("%s/keys/%s.plist", repo->xhp->metadir, hexfp);
806 repokeyd = xbps_plist_dictionary_from_file(rkeyfile);
807 if (xbps_object_type(repokeyd) == XBPS_TYPE_DICTIONARY) {
808 xbps_dbg_printf("[repo] `%s' public key already stored.\n", repo->uri);
809 goto out;
810 }
811 /*
812 * Notify the client and take appropiate action to import
813 * the repository public key. Pass back the public key openssh fingerprint
814 * to the client.
815 */
816 import = xbps_set_cb_state(repo->xhp, XBPS_STATE_REPO_KEY_IMPORT, 0,
817 hexfp, "`%s' repository has been RSA signed by \"%s\"",
818 repo->uri, signedby);
819 if (import <= 0) {
820 rv = EAGAIN;
821 goto out;
822 }
823
824 p = strdup(rkeyfile);
825 dbkeyd = dirname(p);
826 assert(dbkeyd);
827 if (access(dbkeyd, R_OK|W_OK) == -1) {
828 rv = errno;
829 if (rv == ENOENT)
830 rv = xbps_mkpath(dbkeyd, 0755);
831 if (rv != 0) {
832 rv = errno;
833 xbps_dbg_printf("[repo] `%s' cannot create %s: %s\n",
834 repo->uri, dbkeyd, strerror(errno));
835 free(p);
836 goto out;
837 }
838 }
839 free(p);
840
841 repokeyd = xbps_dictionary_create();
842 xbps_dictionary_set(repokeyd, "public-key", pubkey);
843 xbps_dictionary_set_uint16(repokeyd, "public-key-size", pubkey_size);
844 xbps_dictionary_set_cstring_nocopy(repokeyd, "signature-by", signedby);
845
846 if (!xbps_dictionary_externalize_to_file(repokeyd, rkeyfile)) {
847 rv = errno;
848 xbps_dbg_printf("[repo] `%s' failed to externalize %s: %s\n",
849 repo->uri, rkeyfile, strerror(rv));
850 }
851
852out:
853 if (hexfp)
854 free(hexfp);
855 if (repokeyd)
856 xbps_object_release(repokeyd);
857 if (rkeyfile)
858 free(rkeyfile);
859 return rv;
860}
const char * target_arch
Definition xbps.h:640
xbps_array_t repositories
Definition xbps.h:572
char native_arch[64]
Definition xbps.h:680
char metadir[XBPS_MAXPATH]
Definition xbps.h:673
int flags
Definition xbps.h:688
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:592
struct xbps_repo * xbps_repo_open(struct xbps_handle *xhp, const char *url)
Definition repo.c:487
void xbps_repo_release(struct xbps_repo *repo)
Definition repo.c:533
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:427
int xbps_repo_key_import(struct xbps_repo *repo)
Definition repo.c:762
xbps_dictionary_t xbps_repo_get_virtualpkg(struct xbps_repo *repo, const char *pkg)
Definition repo.c:558
xbps_array_t xbps_repo_get_pkg_revdeps(struct xbps_repo *repo, const char *pkg)
Definition repo.c:720
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:388
const char * arch
Definition xbps.h:1436
xbps_dictionary_t idxmeta
Definition xbps.h:1460
bool is_remote
Definition xbps.h:1472
struct xbps_handle * xhp
Definition xbps.h:1430
xbps_dictionary_t idx
Definition xbps.h:1442
xbps_dictionary_t index
Definition xbps.h:1448
const char * uri
Definition xbps.h:1466
Repository structure.
Definition xbps.h:1418
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