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/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 <yaml.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(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype) 513 { 514 yaml_node_item_t *item; 515 yaml_node_pair_t *pair; 516 yaml_node_t *key, *val, *item_val; 517 struct sbuf *buf = sbuf_new_auto(); 518 struct config_entry *temp_config; 519 struct config_value *cv; 520 int i; 521 size_t j; 522 523 pair = node->data.mapping.pairs.start; 524 525 /* Temporary config for configs that may be disabled. */ 526 temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 527 528 while (pair < node->data.mapping.pairs.top) { 529 key = yaml_document_get_node(doc, pair->key); 530 val = yaml_document_get_node(doc, pair->value); 531 532 /* 533 * ignoring silently empty keys can be empty lines 534 * or user mistakes 535 */ 536 if (key->data.scalar.length <= 0) { 537 ++pair; 538 continue; 539 } 540 541 /* 542 * silently skip on purpose to allow user to leave 543 * empty lines without complaining 544 */ 545 if (val->type == YAML_NO_NODE || 546 (val->type == YAML_SCALAR_NODE && 547 val->data.scalar.length <= 0)) { 548 ++pair; 549 continue; 550 } 551 552 sbuf_clear(buf); 553 554 if (conftype == CONFFILE_PKG) { 555 for (j = 0; j < strlen(key->data.scalar.value); ++j) 556 sbuf_putc(buf, 557 toupper(key->data.scalar.value[j])); 558 sbuf_finish(buf); 559 } else if (conftype == CONFFILE_REPO) { 560 /* The CONFFILE_REPO type is more restrictive. Only 561 parse known elements. */ 562 if (strcasecmp(key->data.scalar.value, "url") == 0) 563 sbuf_cpy(buf, "PACKAGESITE"); 564 else if (strcasecmp(key->data.scalar.value, 565 "mirror_type") == 0) 566 sbuf_cpy(buf, "MIRROR_TYPE"); 567 else if (strcasecmp(key->data.scalar.value, 568 "signature_type") == 0) 569 sbuf_cpy(buf, "SIGNATURE_TYPE"); 570 else if (strcasecmp(key->data.scalar.value, 571 "fingerprints") == 0) 572 sbuf_cpy(buf, "FINGERPRINTS"); 573 else if (strcasecmp(key->data.scalar.value, 574 "enabled") == 0) { 575 /* Skip disabled repos. */ 576 if (!boolstr_to_bool(val->data.scalar.value)) 577 goto cleanup; 578 } else { /* Skip unknown entries for future use. */ 579 ++pair; 580 continue; 581 } 582 sbuf_finish(buf); 583 } 584 585 for (i = 0; i < CONFIG_SIZE; i++) { 586 if (strcmp(sbuf_data(buf), c[i].key) == 0) 587 break; 588 } 589 590 /* Silently skip unknown keys to be future compatible. */ 591 if (i == CONFIG_SIZE) { 592 ++pair; 593 continue; 594 } 595 596 /* env has priority over config file */ 597 if (c[i].envset) { 598 ++pair; 599 continue; 600 } 601 602 /* Parse sequence value ["item1", "item2"] */ 603 switch (c[i].type) { 604 case PKG_CONFIG_LIST: 605 if (val->type != YAML_SEQUENCE_NODE) { 606 fprintf(stderr, "Skipping invalid array " 607 "value for %s.\n", c[i].key); 608 ++pair; 609 continue; 610 } 611 item = val->data.sequence.items.start; 612 temp_config[i].list = 613 malloc(sizeof(*temp_config[i].list)); 614 STAILQ_INIT(temp_config[i].list); 615 616 while (item < val->data.sequence.items.top) { 617 item_val = yaml_document_get_node(doc, *item); 618 if (item_val->type != YAML_SCALAR_NODE) { 619 ++item; 620 continue; 621 } 622 cv = malloc(sizeof(struct config_value)); 623 cv->value = 624 strdup(item_val->data.scalar.value); 625 STAILQ_INSERT_TAIL(temp_config[i].list, cv, 626 next); 627 ++item; 628 } 629 break; 630 default: 631 /* Normal string value. */ 632 temp_config[i].value = strdup(val->data.scalar.value); 633 break; 634 } 635 ++pair; 636 } 637 638 /* Repo is enabled, copy over all settings from temp_config. */ 639 for (i = 0; i < CONFIG_SIZE; i++) { 640 if (c[i].envset) 641 continue; 642 switch (c[i].type) { 643 case PKG_CONFIG_LIST: 644 c[i].list = temp_config[i].list; 645 break; 646 default: 647 c[i].value = temp_config[i].value; 648 break; 649 } 650 } 651 652 cleanup: 653 free(temp_config); 654 sbuf_delete(buf); 655 } 656 657 /*- 658 * Parse new repo style configs in style: 659 * Name: 660 * URL: 661 * MIRROR_TYPE: 662 * etc... 663 */ 664 static void 665 parse_repo_file(yaml_document_t *doc, yaml_node_t *node) 666 { 667 yaml_node_pair_t *pair; 668 669 pair = node->data.mapping.pairs.start; 670 while (pair < node->data.mapping.pairs.top) { 671 yaml_node_t *key = yaml_document_get_node(doc, pair->key); 672 yaml_node_t *val = yaml_document_get_node(doc, pair->value); 673 674 if (key->data.scalar.length <= 0) { 675 ++pair; 676 continue; 677 } 678 679 if (val->type != YAML_MAPPING_NODE) { 680 ++pair; 681 continue; 682 } 683 684 config_parse(doc, val, CONFFILE_REPO); 685 ++pair; 686 } 687 } 688 689 690 static int 691 read_conf_file(const char *confpath, pkg_conf_file_t conftype) 692 { 693 FILE *fp; 694 yaml_parser_t parser; 695 yaml_document_t doc; 696 yaml_node_t *node; 697 698 if ((fp = fopen(confpath, "r")) == NULL) { 699 if (errno != ENOENT) 700 err(EXIT_FAILURE, "Unable to open configuration " 701 "file %s", confpath); 702 /* no configuration present */ 703 return (1); 704 } 705 706 yaml_parser_initialize(&parser); 707 yaml_parser_set_input_file(&parser, fp); 708 yaml_parser_load(&parser, &doc); 709 710 node = yaml_document_get_root_node(&doc); 711 712 if (node == NULL || node->type != YAML_MAPPING_NODE) 713 warnx("Invalid configuration format, ignoring the " 714 "configuration file %s", confpath); 715 else { 716 if (conftype == CONFFILE_PKG) 717 config_parse(&doc, node, conftype); 718 else if (conftype == CONFFILE_REPO) 719 parse_repo_file(&doc, node); 720 } 721 722 yaml_document_delete(&doc); 723 yaml_parser_delete(&parser); 724 725 return (0); 726 } 727 728 static int 729 load_repositories(const char *repodir) 730 { 731 struct dirent *ent; 732 DIR *d; 733 char *p; 734 size_t n; 735 char path[MAXPATHLEN]; 736 int ret; 737 738 ret = 0; 739 740 if ((d = opendir(repodir)) == NULL) 741 return (1); 742 743 while ((ent = readdir(d))) { 744 /* Trim out 'repos'. */ 745 if ((n = strlen(ent->d_name)) <= 5) 746 continue; 747 p = &ent->d_name[n - 5]; 748 if (strcmp(p, ".conf") == 0) { 749 snprintf(path, sizeof(path), "%s%s%s", 750 repodir, 751 repodir[strlen(repodir) - 1] == '/' ? "" : "/", 752 ent->d_name); 753 if (access(path, F_OK) == 0 && 754 read_conf_file(path, CONFFILE_REPO)) { 755 ret = 1; 756 goto cleanup; 757 } 758 } 759 } 760 761 cleanup: 762 closedir(d); 763 764 return (ret); 765 } 766 767 int 768 config_init(void) 769 { 770 char *val; 771 int i; 772 const char *localbase; 773 char *env_list_item; 774 char confpath[MAXPATHLEN]; 775 struct config_value *cv; 776 char abi[BUFSIZ]; 777 778 for (i = 0; i < CONFIG_SIZE; i++) { 779 val = getenv(c[i].key); 780 if (val != NULL) { 781 c[i].envset = true; 782 switch (c[i].type) { 783 case PKG_CONFIG_LIST: 784 /* Split up comma-separated items from env. */ 785 c[i].list = malloc(sizeof(*c[i].list)); 786 STAILQ_INIT(c[i].list); 787 for (env_list_item = strtok(val, ","); 788 env_list_item != NULL; 789 env_list_item = strtok(NULL, ",")) { 790 cv = 791 malloc(sizeof(struct config_value)); 792 cv->value = 793 strdup(env_list_item); 794 STAILQ_INSERT_TAIL(c[i].list, cv, 795 next); 796 } 797 break; 798 default: 799 c[i].val = val; 800 break; 801 } 802 } 803 } 804 805 /* Read LOCALBASE/etc/pkg.conf first. */ 806 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 807 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 808 localbase); 809 810 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 811 CONFFILE_PKG)) 812 goto finalize; 813 814 /* Then read in all repos from REPOS_DIR list of directories. */ 815 if (c[REPOS_DIR].list == NULL) { 816 c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 817 STAILQ_INIT(c[REPOS_DIR].list); 818 cv = malloc(sizeof(struct config_value)); 819 cv->value = strdup("/etc/pkg"); 820 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 821 cv = malloc(sizeof(struct config_value)); 822 if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 823 goto finalize; 824 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 825 } 826 827 STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 828 if (load_repositories(cv->value)) 829 goto finalize; 830 831 finalize: 832 if (c[ABI].val == NULL && c[ABI].value == NULL) { 833 if (pkg_get_myabi(abi, BUFSIZ) != 0) 834 errx(EXIT_FAILURE, "Failed to determine the system " 835 "ABI"); 836 c[ABI].val = abi; 837 } 838 839 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 840 841 return (0); 842 } 843 844 int 845 config_string(pkg_config_key k, const char **val) 846 { 847 if (c[k].type != PKG_CONFIG_STRING) 848 return (-1); 849 850 if (c[k].value != NULL) 851 *val = c[k].value; 852 else 853 *val = c[k].val; 854 855 return (0); 856 } 857 858 int 859 config_bool(pkg_config_key k, bool *val) 860 { 861 const char *value; 862 863 if (c[k].type != PKG_CONFIG_BOOL) 864 return (-1); 865 866 *val = false; 867 868 if (c[k].value != NULL) 869 value = c[k].value; 870 else 871 value = c[k].val; 872 873 if (boolstr_to_bool(value)) 874 *val = true; 875 876 return (0); 877 } 878 879 void 880 config_finish(void) { 881 int i; 882 883 for (i = 0; i < CONFIG_SIZE; i++) 884 free(c[i].value); 885 } 886