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