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 bool main_only; /* Only set in pkg.conf. */ 70 }; 71 72 static 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 138 static const char * 139 elf_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 150 static const char * 151 aeabi_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 282 static int 283 pkg_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 475 cleanup: 476 if (elf != NULL) 477 elf_end(elf); 478 479 close(fd); 480 return (ret); 481 } 482 483 static void 484 subst_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 508 static int 509 boolstr_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 519 static void 520 config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype) 521 { 522 struct sbuf *buf = sbuf_new_auto(); 523 const 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 case PKG_CONFIG_BOOL: 598 temp_config[i].value = 599 strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 600 break; 601 default: 602 /* Normal string value. */ 603 temp_config[i].value = strdup(ucl_object_tostring(cur)); 604 break; 605 } 606 } 607 608 /* Repo is enabled, copy over all settings from temp_config. */ 609 for (i = 0; i < CONFIG_SIZE; i++) { 610 if (c[i].envset) 611 continue; 612 /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 613 if (conftype != CONFFILE_PKG && c[i].main_only == true) 614 continue; 615 switch (c[i].type) { 616 case PKG_CONFIG_LIST: 617 c[i].list = temp_config[i].list; 618 break; 619 default: 620 c[i].value = temp_config[i].value; 621 break; 622 } 623 } 624 625 cleanup: 626 free(temp_config); 627 sbuf_delete(buf); 628 } 629 630 /*- 631 * Parse new repo style configs in style: 632 * Name: 633 * URL: 634 * MIRROR_TYPE: 635 * etc... 636 */ 637 static void 638 parse_repo_file(ucl_object_t *obj) 639 { 640 ucl_object_iter_t it = NULL; 641 const ucl_object_t *cur; 642 const char *key; 643 644 while ((cur = ucl_iterate_object(obj, &it, true))) { 645 key = ucl_object_key(cur); 646 647 if (key == NULL) 648 continue; 649 650 if (cur->type != UCL_OBJECT) 651 continue; 652 653 config_parse(cur, CONFFILE_REPO); 654 } 655 } 656 657 658 static int 659 read_conf_file(const char *confpath, pkg_conf_file_t conftype) 660 { 661 struct ucl_parser *p; 662 ucl_object_t *obj = NULL; 663 664 p = ucl_parser_new(0); 665 666 if (!ucl_parser_add_file(p, confpath)) { 667 if (errno != ENOENT) 668 errx(EXIT_FAILURE, "Unable to parse configuration " 669 "file %s: %s", confpath, ucl_parser_get_error(p)); 670 ucl_parser_free(p); 671 /* no configuration present */ 672 return (1); 673 } 674 675 obj = ucl_parser_get_object(p); 676 if (obj->type != UCL_OBJECT) 677 warnx("Invalid configuration format, ignoring the " 678 "configuration file %s", confpath); 679 else { 680 if (conftype == CONFFILE_PKG) 681 config_parse(obj, conftype); 682 else if (conftype == CONFFILE_REPO) 683 parse_repo_file(obj); 684 } 685 686 ucl_object_unref(obj); 687 ucl_parser_free(p); 688 689 return (0); 690 } 691 692 static int 693 load_repositories(const char *repodir) 694 { 695 struct dirent *ent; 696 DIR *d; 697 char *p; 698 size_t n; 699 char path[MAXPATHLEN]; 700 int ret; 701 702 ret = 0; 703 704 if ((d = opendir(repodir)) == NULL) 705 return (1); 706 707 while ((ent = readdir(d))) { 708 /* Trim out 'repos'. */ 709 if ((n = strlen(ent->d_name)) <= 5) 710 continue; 711 p = &ent->d_name[n - 5]; 712 if (strcmp(p, ".conf") == 0) { 713 snprintf(path, sizeof(path), "%s%s%s", 714 repodir, 715 repodir[strlen(repodir) - 1] == '/' ? "" : "/", 716 ent->d_name); 717 if (access(path, F_OK) == 0 && 718 read_conf_file(path, CONFFILE_REPO)) { 719 ret = 1; 720 goto cleanup; 721 } 722 } 723 } 724 725 cleanup: 726 closedir(d); 727 728 return (ret); 729 } 730 731 int 732 config_init(void) 733 { 734 char *val; 735 int i; 736 const char *localbase; 737 char *env_list_item; 738 char confpath[MAXPATHLEN]; 739 struct config_value *cv; 740 char abi[BUFSIZ]; 741 742 for (i = 0; i < CONFIG_SIZE; i++) { 743 val = getenv(c[i].key); 744 if (val != NULL) { 745 c[i].envset = true; 746 switch (c[i].type) { 747 case PKG_CONFIG_LIST: 748 /* Split up comma-separated items from env. */ 749 c[i].list = malloc(sizeof(*c[i].list)); 750 STAILQ_INIT(c[i].list); 751 for (env_list_item = strtok(val, ","); 752 env_list_item != NULL; 753 env_list_item = strtok(NULL, ",")) { 754 cv = 755 malloc(sizeof(struct config_value)); 756 cv->value = 757 strdup(env_list_item); 758 STAILQ_INSERT_TAIL(c[i].list, cv, 759 next); 760 } 761 break; 762 default: 763 c[i].val = val; 764 break; 765 } 766 } 767 } 768 769 /* Read LOCALBASE/etc/pkg.conf first. */ 770 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 771 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 772 localbase); 773 774 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 775 CONFFILE_PKG)) 776 goto finalize; 777 778 /* Then read in all repos from REPOS_DIR list of directories. */ 779 if (c[REPOS_DIR].list == NULL) { 780 c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 781 STAILQ_INIT(c[REPOS_DIR].list); 782 cv = malloc(sizeof(struct config_value)); 783 cv->value = strdup("/etc/pkg"); 784 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 785 cv = malloc(sizeof(struct config_value)); 786 if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 787 goto finalize; 788 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 789 } 790 791 STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 792 if (load_repositories(cv->value)) 793 goto finalize; 794 795 finalize: 796 if (c[ABI].val == NULL && c[ABI].value == NULL) { 797 if (pkg_get_myabi(abi, BUFSIZ) != 0) 798 errx(EXIT_FAILURE, "Failed to determine the system " 799 "ABI"); 800 c[ABI].val = abi; 801 } 802 803 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 804 805 return (0); 806 } 807 808 int 809 config_string(pkg_config_key k, const char **val) 810 { 811 if (c[k].type != PKG_CONFIG_STRING) 812 return (-1); 813 814 if (c[k].value != NULL) 815 *val = c[k].value; 816 else 817 *val = c[k].val; 818 819 return (0); 820 } 821 822 int 823 config_bool(pkg_config_key k, bool *val) 824 { 825 const char *value; 826 827 if (c[k].type != PKG_CONFIG_BOOL) 828 return (-1); 829 830 *val = false; 831 832 if (c[k].value != NULL) 833 value = c[k].value; 834 else 835 value = c[k].val; 836 837 if (boolstr_to_bool(value)) 838 *val = true; 839 840 return (0); 841 } 842 843 void 844 config_finish(void) { 845 int i; 846 847 for (i = 0; i < CONFIG_SIZE; i++) 848 free(c[i].value); 849 } 850