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