1/*- 2 * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> 3 * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 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 AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD$"); 30 31#include <sys/param.h> 32#include <sys/queue.h> 33#include <sys/sbuf.h> 34#include <sys/elf_common.h> 35#include <sys/endian.h> 36#include <sys/types.h> 37 38#include <assert.h> 39#include <dirent.h> 40#include <ucl.h> 41#include <ctype.h> 42#include <err.h> 43#include <errno.h> 44#include <fcntl.h> 45#include <gelf.h> 46#include <inttypes.h> 47#include <paths.h> 48#include <stdbool.h> 49#include <string.h> 50#include <unistd.h> 51 52#include "elf_tables.h" 53#include "config.h" 54 55#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 56 57struct config_value { 58 char *value; 59 STAILQ_ENTRY(config_value) next; 60}; 61 62struct config_entry { 63 uint8_t type; 64 const char *key; 65 const char *val; 66 char *value; 67 STAILQ_HEAD(, config_value) *list; 68 bool envset; 69 bool main_only; /* Only set in pkg.conf. */ 70}; 71 72static struct config_entry c[] = { 73 [PACKAGESITE] = { 74 PKG_CONFIG_STRING, 75 "PACKAGESITE", 76 URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 77 NULL, 78 NULL, 79 false, 80 false, 81 }, 82 [ABI] = { 83 PKG_CONFIG_STRING, 84 "ABI", 85 NULL, 86 NULL, 87 NULL, 88 false, 89 true, 90 }, 91 [MIRROR_TYPE] = { 92 PKG_CONFIG_STRING, 93 "MIRROR_TYPE", 94 "SRV", 95 NULL, 96 NULL, 97 false, 98 false, 99 }, 100 [ASSUME_ALWAYS_YES] = { 101 PKG_CONFIG_BOOL, 102 "ASSUME_ALWAYS_YES", 103 "NO", 104 NULL, 105 NULL, 106 false, 107 true, 108 }, 109 [SIGNATURE_TYPE] = { 110 PKG_CONFIG_STRING, 111 "SIGNATURE_TYPE", 112 NULL, 113 NULL, 114 NULL, 115 false, 116 false, 117 }, 118 [FINGERPRINTS] = { 119 PKG_CONFIG_STRING, 120 "FINGERPRINTS", 121 NULL, 122 NULL, 123 NULL, 124 false, 125 false, 126 }, 127 [REPOS_DIR] = { 128 PKG_CONFIG_LIST, 129 "REPOS_DIR", 130 NULL, 131 NULL, 132 NULL, 133 false, 134 true, 135 }, 136 [PUBKEY] = { 137 PKG_CONFIG_STRING, 138 "PUBKEY", 139 NULL, 140 NULL, 141 NULL, 142 false, 143 false 144 } 145}; 146 147static const char * 148elf_corres_to_string(struct _elf_corres *m, int e) 149{ 150 int i; 151 152 for (i = 0; m[i].string != NULL; i++) 153 if (m[i].elf_nb == e) 154 return (m[i].string); 155 156 return ("unknown"); 157} 158 159static const char * 160aeabi_parse_arm_attributes(void *data, size_t length) 161{ 162 uint32_t sect_len; 163 uint8_t *section = data; 164 165#define MOVE(len) do { \ 166 assert(length >= (len)); \ 167 section += (len); \ 168 length -= (len); \ 169} while (0) 170 171 if (length == 0 || *section != 'A') 172 return (NULL); 173 174 MOVE(1); 175 176 /* Read the section length */ 177 if (length < sizeof(sect_len)) 178 return (NULL); 179 180 memcpy(§_len, section, sizeof(sect_len)); 181 182 /* 183 * The section length should be no longer than the section it is within 184 */ 185 if (sect_len > length) 186 return (NULL); 187 188 MOVE(sizeof(sect_len)); 189 190 /* Skip the vendor name */ 191 while (length != 0) { 192 if (*section == '\0') 193 break; 194 MOVE(1); 195 } 196 if (length == 0) 197 return (NULL); 198 MOVE(1); 199 200 while (length != 0) { 201 uint32_t tag_length; 202 203 switch(*section) { 204 case 1: /* Tag_File */ 205 MOVE(1); 206 if (length < sizeof(tag_length)) 207 return (NULL); 208 memcpy(&tag_length, section, sizeof(tag_length)); 209 break; 210 case 2: /* Tag_Section */ 211 case 3: /* Tag_Symbol */ 212 default: 213 return (NULL); 214 } 215 /* At least space for the tag and size */ 216 if (tag_length <= 5) 217 return (NULL); 218 tag_length--; 219 /* Check the tag fits */ 220 if (tag_length > length) 221 return (NULL); 222 223#define MOVE_TAG(len) do { \ 224 assert(tag_length >= (len)); \ 225 MOVE(len); \ 226 tag_length -= (len); \ 227} while(0) 228 229 MOVE(sizeof(tag_length)); 230 tag_length -= sizeof(tag_length); 231 232 while (tag_length != 0) { 233 uint8_t tag; 234 235 assert(tag_length >= length); 236 237 tag = *section; 238 MOVE_TAG(1); 239 240 /* 241 * These tag values come from: 242 * 243 * Addenda to, and Errata in, the ABI for the 244 * ARM Architecture. Release 2.08, section 2.3. 245 */ 246 if (tag == 6) { /* == Tag_CPU_arch */ 247 uint8_t val; 248 249 val = *section; 250 /* 251 * We don't support values that require 252 * more than one byte. 253 */ 254 if (val & (1 << 7)) 255 return (NULL); 256 257 /* We have an ARMv4 or ARMv5 */ 258 if (val <= 5) 259 return ("arm"); 260 else /* We have an ARMv6+ */ 261 return ("armv6"); 262 } else if (tag == 4 || tag == 5 || tag == 32 || 263 tag == 65 || tag == 67) { 264 while (*section != '\0' && length != 0) 265 MOVE_TAG(1); 266 if (tag_length == 0) 267 return (NULL); 268 /* Skip the last byte */ 269 MOVE_TAG(1); 270 } else if ((tag >= 7 && tag <= 31) || tag == 34 || 271 tag == 36 || tag == 38 || tag == 42 || tag == 44 || 272 tag == 64 || tag == 66 || tag == 68 || tag == 70) { 273 /* Skip the uleb128 data */ 274 while (*section & (1 << 7) && length != 0) 275 MOVE_TAG(1); 276 if (tag_length == 0) 277 return (NULL); 278 /* Skip the last byte */ 279 MOVE_TAG(1); 280 } else 281 return (NULL); 282#undef MOVE_TAG 283 } 284 285 break; 286 } 287 return (NULL); 288#undef MOVE 289} 290 291static int 292pkg_get_myabi(char *dest, size_t sz) 293{ 294 Elf *elf; 295 Elf_Data *data; 296 Elf_Note note; 297 Elf_Scn *scn; 298 char *src, *osname; 299 const char *arch, *abi, *fpu, *endian_corres_str; 300 const char *wordsize_corres_str; 301 GElf_Ehdr elfhdr; 302 GElf_Shdr shdr; 303 int fd, i, ret; 304 uint32_t version; 305 306 version = 0; 307 ret = -1; 308 scn = NULL; 309 abi = NULL; 310 311 if (elf_version(EV_CURRENT) == EV_NONE) { 312 warnx("ELF library initialization failed: %s", 313 elf_errmsg(-1)); 314 return (-1); 315 } 316 317 if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 318 warn("open()"); 319 return (-1); 320 } 321 322 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 323 ret = -1; 324 warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 325 goto cleanup; 326 } 327 328 if (gelf_getehdr(elf, &elfhdr) == NULL) { 329 ret = -1; 330 warn("getehdr() failed: %s.", elf_errmsg(-1)); 331 goto cleanup; 332 } 333 while ((scn = elf_nextscn(elf, scn)) != NULL) { 334 if (gelf_getshdr(scn, &shdr) != &shdr) { 335 ret = -1; 336 warn("getshdr() failed: %s.", elf_errmsg(-1)); 337 goto cleanup; 338 } 339 340 if (shdr.sh_type == SHT_NOTE) 341 break; 342 } 343 344 if (scn == NULL) { 345 ret = -1; 346 warn("failed to get the note section"); 347 goto cleanup; 348 } 349 350 data = elf_getdata(scn, NULL); 351 src = data->d_buf; 352 for (;;) { 353 memcpy(¬e, src, sizeof(Elf_Note)); 354 src += sizeof(Elf_Note); 355 if (note.n_type == NT_VERSION) 356 break; 357 src += note.n_namesz + note.n_descsz; 358 } 359 osname = src; 360 src += roundup2(note.n_namesz, 4); 361 if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 362 version = be32dec(src); 363 else 364 version = le32dec(src); 365 366 for (i = 0; osname[i] != '\0'; i++) 367 osname[i] = (char)tolower(osname[i]); 368 369 wordsize_corres_str = elf_corres_to_string(wordsize_corres, 370 (int)elfhdr.e_ident[EI_CLASS]); 371 372 arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 373 374 snprintf(dest, sz, "%s:%d", 375 osname, version / 100000); 376 377 ret = 0; 378 379 switch (elfhdr.e_machine) { 380 case EM_ARM: 381 endian_corres_str = elf_corres_to_string(endian_corres, 382 (int)elfhdr.e_ident[EI_DATA]); 383 384 /* FreeBSD doesn't support the hard-float ABI yet */ 385 fpu = "softfp"; 386 if ((elfhdr.e_flags & 0xFF000000) != 0) { 387 const char *sh_name = NULL; 388 size_t shstrndx; 389 390 /* This is an EABI file, the conformance level is set */ 391 abi = "eabi"; 392 /* Find which TARGET_ARCH we are building for. */ 393 elf_getshdrstrndx(elf, &shstrndx); 394 while ((scn = elf_nextscn(elf, scn)) != NULL) { 395 sh_name = NULL; 396 if (gelf_getshdr(scn, &shdr) != &shdr) { 397 scn = NULL; 398 break; 399 } 400 401 sh_name = elf_strptr(elf, shstrndx, 402 shdr.sh_name); 403 if (sh_name == NULL) 404 continue; 405 if (strcmp(".ARM.attributes", sh_name) == 0) 406 break; 407 } 408 if (scn != NULL && sh_name != NULL) { 409 data = elf_getdata(scn, NULL); 410 /* 411 * Prior to FreeBSD 10.0 libelf would return 412 * NULL from elf_getdata on the .ARM.attributes 413 * section. As this was the first release to 414 * get armv6 support assume a NULL value means 415 * arm. 416 * 417 * This assumption can be removed when 9.x 418 * is unsupported. 419 */ 420 if (data != NULL) { 421 arch = aeabi_parse_arm_attributes( 422 data->d_buf, data->d_size); 423 if (arch == NULL) { 424 ret = 1; 425 warn("unknown ARM ARCH"); 426 goto cleanup; 427 } 428 } 429 } else { 430 ret = 1; 431 warn("Unable to find the .ARM.attributes " 432 "section"); 433 goto cleanup; 434 } 435 } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 436 /* 437 * EABI executables all have this field set to 438 * ELFOSABI_NONE, therefore it must be an oabi file. 439 */ 440 abi = "oabi"; 441 } else { 442 ret = 1; 443 warn("unknown ARM ABI"); 444 goto cleanup; 445 } 446 snprintf(dest + strlen(dest), sz - strlen(dest), 447 ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 448 endian_corres_str, abi, fpu); 449 break; 450 case EM_MIPS: 451 /* 452 * this is taken from binutils sources: 453 * include/elf/mips.h 454 * mapping is figured out from binutils: 455 * gas/config/tc-mips.c 456 */ 457 switch (elfhdr.e_flags & EF_MIPS_ABI) { 458 case E_MIPS_ABI_O32: 459 abi = "o32"; 460 break; 461 case E_MIPS_ABI_N32: 462 abi = "n32"; 463 break; 464 default: 465 if (elfhdr.e_ident[EI_DATA] == 466 ELFCLASS32) 467 abi = "o32"; 468 else if (elfhdr.e_ident[EI_DATA] == 469 ELFCLASS64) 470 abi = "n64"; 471 break; 472 } 473 endian_corres_str = elf_corres_to_string(endian_corres, 474 (int)elfhdr.e_ident[EI_DATA]); 475 476 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 477 arch, wordsize_corres_str, endian_corres_str, abi); 478 break; 479 default: 480 snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 481 arch, wordsize_corres_str); 482 } 483 484cleanup: 485 if (elf != NULL) 486 elf_end(elf); 487 488 close(fd); 489 return (ret); 490} 491 492static void 493subst_packagesite(const char *abi) 494{ 495 struct sbuf *newval; 496 const char *variable_string; 497 const char *oldval; 498 499 if (c[PACKAGESITE].value != NULL) 500 oldval = c[PACKAGESITE].value; 501 else 502 oldval = c[PACKAGESITE].val; 503 504 if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 505 return; 506 507 newval = sbuf_new_auto(); 508 sbuf_bcat(newval, oldval, variable_string - oldval); 509 sbuf_cat(newval, abi); 510 sbuf_cat(newval, variable_string + strlen("${ABI}")); 511 sbuf_finish(newval); 512 513 free(c[PACKAGESITE].value); 514 c[PACKAGESITE].value = strdup(sbuf_data(newval)); 515} 516 517static int 518boolstr_to_bool(const char *str) 519{ 520 if (str != NULL && (strcasecmp(str, "true") == 0 || 521 strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 522 str[0] == '1')) 523 return (true); 524 525 return (false); 526} 527 528static void 529config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype) 530{ 531 struct sbuf *buf = sbuf_new_auto(); 532 const ucl_object_t *cur, *seq; 533 ucl_object_iter_t it = NULL, itseq = NULL; 534 struct config_entry *temp_config; 535 struct config_value *cv; 536 const char *key; 537 int i; 538 size_t j; 539 540 /* Temporary config for configs that may be disabled. */ 541 temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 542 543 while ((cur = ucl_iterate_object(obj, &it, true))) { 544 key = ucl_object_key(cur); 545 if (key == NULL) 546 continue; 547 sbuf_clear(buf); 548 549 if (conftype == CONFFILE_PKG) { 550 for (j = 0; j < strlen(key); ++j) 551 sbuf_putc(buf, key[j]); 552 sbuf_finish(buf); 553 } else if (conftype == CONFFILE_REPO) { 554 if (strcasecmp(key, "url") == 0) 555 sbuf_cpy(buf, "PACKAGESITE"); 556 else if (strcasecmp(key, "mirror_type") == 0) 557 sbuf_cpy(buf, "MIRROR_TYPE"); 558 else if (strcasecmp(key, "signature_type") == 0) 559 sbuf_cpy(buf, "SIGNATURE_TYPE"); 560 else if (strcasecmp(key, "fingerprints") == 0) 561 sbuf_cpy(buf, "FINGERPRINTS"); 562 else if (strcasecmp(key, "pubkey") == 0) 563 sbuf_cpy(buf, "PUBKEY"); 564 else if (strcasecmp(key, "enabled") == 0) { 565 if ((cur->type != UCL_BOOLEAN) || 566 !ucl_object_toboolean(cur)) 567 goto cleanup; 568 } else 569 continue; 570 sbuf_finish(buf); 571 } 572 573 for (i = 0; i < CONFIG_SIZE; i++) { 574 if (strcmp(sbuf_data(buf), c[i].key) == 0) 575 break; 576 } 577 578 /* Silently skip unknown keys to be future compatible. */ 579 if (i == CONFIG_SIZE) 580 continue; 581 582 /* env has priority over config file */ 583 if (c[i].envset) 584 continue; 585 586 /* Parse sequence value ["item1", "item2"] */ 587 switch (c[i].type) { 588 case PKG_CONFIG_LIST: 589 if (cur->type != UCL_ARRAY) { 590 warnx("Skipping invalid array " 591 "value for %s.\n", c[i].key); 592 continue; 593 } 594 temp_config[i].list = 595 malloc(sizeof(*temp_config[i].list)); 596 STAILQ_INIT(temp_config[i].list); 597 598 while ((seq = ucl_iterate_object(cur, &itseq, true))) { 599 if (seq->type != UCL_STRING) 600 continue; 601 cv = malloc(sizeof(struct config_value)); 602 cv->value = 603 strdup(ucl_object_tostring(seq)); 604 STAILQ_INSERT_TAIL(temp_config[i].list, cv, 605 next); 606 } 607 break; 608 case PKG_CONFIG_BOOL: 609 temp_config[i].value = 610 strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 611 break; 612 default: 613 /* Normal string value. */ 614 temp_config[i].value = strdup(ucl_object_tostring(cur)); 615 break; 616 } 617 } 618 619 /* Repo is enabled, copy over all settings from temp_config. */ 620 for (i = 0; i < CONFIG_SIZE; i++) { 621 if (c[i].envset) 622 continue; 623 /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 624 if (conftype != CONFFILE_PKG && c[i].main_only == true) 625 continue; 626 switch (c[i].type) { 627 case PKG_CONFIG_LIST: 628 c[i].list = temp_config[i].list; 629 break; 630 default: 631 c[i].value = temp_config[i].value; 632 break; 633 } 634 } 635 636cleanup: 637 free(temp_config); 638 sbuf_delete(buf); 639} 640 641/*- 642 * Parse new repo style configs in style: 643 * Name: 644 * URL: 645 * MIRROR_TYPE: 646 * etc... 647 */ 648static void 649parse_repo_file(ucl_object_t *obj) 650{ 651 ucl_object_iter_t it = NULL; 652 const ucl_object_t *cur; 653 const char *key; 654 655 while ((cur = ucl_iterate_object(obj, &it, true))) { 656 key = ucl_object_key(cur); 657 658 if (key == NULL) 659 continue; 660 661 if (cur->type != UCL_OBJECT) 662 continue; 663 664 config_parse(cur, CONFFILE_REPO); 665 } 666} 667 668 669static int 670read_conf_file(const char *confpath, pkg_conf_file_t conftype) 671{ 672 struct ucl_parser *p; 673 ucl_object_t *obj = NULL; 674 675 p = ucl_parser_new(0); 676 677 if (!ucl_parser_add_file(p, confpath)) { 678 if (errno != ENOENT) 679 errx(EXIT_FAILURE, "Unable to parse configuration " 680 "file %s: %s", confpath, ucl_parser_get_error(p)); 681 ucl_parser_free(p); 682 /* no configuration present */ 683 return (1); 684 } 685 686 obj = ucl_parser_get_object(p); 687 if (obj->type != UCL_OBJECT) 688 warnx("Invalid configuration format, ignoring the " 689 "configuration file %s", confpath); 690 else { 691 if (conftype == CONFFILE_PKG) 692 config_parse(obj, conftype); 693 else if (conftype == CONFFILE_REPO) 694 parse_repo_file(obj); 695 } 696 697 ucl_object_unref(obj); 698 ucl_parser_free(p); 699 700 return (0); 701} 702 703static int 704load_repositories(const char *repodir) 705{ 706 struct dirent *ent; 707 DIR *d; 708 char *p; 709 size_t n; 710 char path[MAXPATHLEN]; 711 int ret; 712 713 ret = 0; 714 715 if ((d = opendir(repodir)) == NULL) 716 return (1); 717 718 while ((ent = readdir(d))) { 719 /* Trim out 'repos'. */ 720 if ((n = strlen(ent->d_name)) <= 5) 721 continue; 722 p = &ent->d_name[n - 5]; 723 if (strcmp(p, ".conf") == 0) { 724 snprintf(path, sizeof(path), "%s%s%s", 725 repodir, 726 repodir[strlen(repodir) - 1] == '/' ? "" : "/", 727 ent->d_name); 728 if (access(path, F_OK) == 0 && 729 read_conf_file(path, CONFFILE_REPO)) { 730 ret = 1; 731 goto cleanup; 732 } 733 } 734 } 735 736cleanup: 737 closedir(d); 738 739 return (ret); 740} 741 742int 743config_init(void) 744{ 745 char *val; 746 int i; 747 const char *localbase; 748 char *env_list_item; 749 char confpath[MAXPATHLEN]; 750 struct config_value *cv; 751 char abi[BUFSIZ]; 752 753 for (i = 0; i < CONFIG_SIZE; i++) { 754 val = getenv(c[i].key); 755 if (val != NULL) { 756 c[i].envset = true; 757 switch (c[i].type) { 758 case PKG_CONFIG_LIST: 759 /* Split up comma-separated items from env. */ 760 c[i].list = malloc(sizeof(*c[i].list)); 761 STAILQ_INIT(c[i].list); 762 for (env_list_item = strtok(val, ","); 763 env_list_item != NULL; 764 env_list_item = strtok(NULL, ",")) { 765 cv = 766 malloc(sizeof(struct config_value)); 767 cv->value = 768 strdup(env_list_item); 769 STAILQ_INSERT_TAIL(c[i].list, cv, 770 next); 771 } 772 break; 773 default: 774 c[i].val = val; 775 break; 776 } 777 } 778 } 779 780 /* Read LOCALBASE/etc/pkg.conf first. */ 781 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 782 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 783 localbase); 784 785 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 786 CONFFILE_PKG)) 787 goto finalize; 788 789 /* Then read in all repos from REPOS_DIR list of directories. */ 790 if (c[REPOS_DIR].list == NULL) { 791 c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 792 STAILQ_INIT(c[REPOS_DIR].list); 793 cv = malloc(sizeof(struct config_value)); 794 cv->value = strdup("/etc/pkg"); 795 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 796 cv = malloc(sizeof(struct config_value)); 797 if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 798 goto finalize; 799 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 800 } 801 802 STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 803 if (load_repositories(cv->value)) 804 goto finalize; 805 806finalize: 807 if (c[ABI].val == NULL && c[ABI].value == NULL) { 808 if (pkg_get_myabi(abi, BUFSIZ) != 0) 809 errx(EXIT_FAILURE, "Failed to determine the system " 810 "ABI"); 811 c[ABI].val = abi; 812 } 813 814 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 815 816 return (0); 817} 818 819int 820config_string(pkg_config_key k, const char **val) 821{ 822 if (c[k].type != PKG_CONFIG_STRING) 823 return (-1); 824 825 if (c[k].value != NULL) 826 *val = c[k].value; 827 else 828 *val = c[k].val; 829 830 return (0); 831} 832 833int 834config_bool(pkg_config_key k, bool *val) 835{ 836 const char *value; 837 838 if (c[k].type != PKG_CONFIG_BOOL) 839 return (-1); 840 841 *val = false; 842 843 if (c[k].value != NULL) 844 value = c[k].value; 845 else 846 value = c[k].val; 847 848 if (boolstr_to_bool(value)) 849 *val = true; 850 851 return (0); 852} 853 854void 855config_finish(void) { 856 int i; 857 858 for (i = 0; i < CONFIG_SIZE; i++) 859 free(c[i].value); 860} 861