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