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