1247841Sbapt/*- 2263038Sbapt * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> 3263038Sbapt * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 4247841Sbapt * All rights reserved. 5247841Sbapt * 6247841Sbapt * Redistribution and use in source and binary forms, with or without 7247841Sbapt * modification, are permitted provided that the following conditions 8247841Sbapt * are met: 9247841Sbapt * 1. Redistributions of source code must retain the above copyright 10247841Sbapt * notice, this list of conditions and the following disclaimer. 11247841Sbapt * 2. Redistributions in binary form must reproduce the above copyright 12247841Sbapt * notice, this list of conditions and the following disclaimer in the 13247841Sbapt * documentation and/or other materials provided with the distribution. 14247841Sbapt * 15247841Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16247841Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17247841Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18247841Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19247841Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20247841Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21247841Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22247841Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23247841Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24247841Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25247841Sbapt * SUCH DAMAGE. 26247841Sbapt */ 27247841Sbapt 28247841Sbapt#include <sys/cdefs.h> 29247841Sbapt__FBSDID("$FreeBSD$"); 30247841Sbapt 31247841Sbapt#include <sys/param.h> 32247841Sbapt#include <sys/sbuf.h> 33247841Sbapt#include <sys/elf_common.h> 34247841Sbapt#include <sys/endian.h> 35263038Sbapt#include <sys/types.h> 36247841Sbapt 37263038Sbapt#include <dirent.h> 38263038Sbapt#include <ucl.h> 39247841Sbapt#include <ctype.h> 40247841Sbapt#include <err.h> 41247841Sbapt#include <errno.h> 42247841Sbapt#include <fcntl.h> 43247841Sbapt#include <gelf.h> 44247841Sbapt#include <inttypes.h> 45247841Sbapt#include <paths.h> 46247841Sbapt#include <stdbool.h> 47247841Sbapt#include <string.h> 48247841Sbapt#include <unistd.h> 49247841Sbapt 50247841Sbapt#include "elf_tables.h" 51247841Sbapt#include "config.h" 52247841Sbapt 53247841Sbapt#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 54247841Sbapt 55263038Sbaptstruct config_value { 56263038Sbapt char *value; 57263038Sbapt STAILQ_ENTRY(config_value) next; 58263038Sbapt}; 59263038Sbapt 60247841Sbaptstruct config_entry { 61247841Sbapt uint8_t type; 62247841Sbapt const char *key; 63247841Sbapt const char *val; 64247841Sbapt char *value; 65263038Sbapt STAILQ_HEAD(, config_value) *list; 66247841Sbapt bool envset; 67263623Sbdrewery bool main_only; /* Only set in pkg.conf. */ 68247841Sbapt}; 69247841Sbapt 70247841Sbaptstatic struct config_entry c[] = { 71247841Sbapt [PACKAGESITE] = { 72247841Sbapt PKG_CONFIG_STRING, 73247841Sbapt "PACKAGESITE", 74263038Sbapt URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 75247841Sbapt NULL, 76263038Sbapt NULL, 77247841Sbapt false, 78263623Sbdrewery false, 79247841Sbapt }, 80247841Sbapt [ABI] = { 81247841Sbapt PKG_CONFIG_STRING, 82247841Sbapt "ABI", 83247841Sbapt NULL, 84247841Sbapt NULL, 85263038Sbapt NULL, 86247841Sbapt false, 87263623Sbdrewery true, 88247841Sbapt }, 89247841Sbapt [MIRROR_TYPE] = { 90247841Sbapt PKG_CONFIG_STRING, 91247841Sbapt "MIRROR_TYPE", 92247841Sbapt "SRV", 93247841Sbapt NULL, 94263038Sbapt NULL, 95247841Sbapt false, 96263623Sbdrewery false, 97247841Sbapt }, 98247841Sbapt [ASSUME_ALWAYS_YES] = { 99247841Sbapt PKG_CONFIG_BOOL, 100247841Sbapt "ASSUME_ALWAYS_YES", 101247841Sbapt "NO", 102247841Sbapt NULL, 103263038Sbapt NULL, 104247841Sbapt false, 105263623Sbdrewery true, 106263038Sbapt }, 107263038Sbapt [SIGNATURE_TYPE] = { 108263038Sbapt PKG_CONFIG_STRING, 109263038Sbapt "SIGNATURE_TYPE", 110263038Sbapt NULL, 111263038Sbapt NULL, 112263038Sbapt NULL, 113263038Sbapt false, 114263623Sbdrewery false, 115263038Sbapt }, 116263038Sbapt [FINGERPRINTS] = { 117263038Sbapt PKG_CONFIG_STRING, 118263038Sbapt "FINGERPRINTS", 119263038Sbapt NULL, 120263038Sbapt NULL, 121263038Sbapt NULL, 122263038Sbapt false, 123263623Sbdrewery false, 124263038Sbapt }, 125263038Sbapt [REPOS_DIR] = { 126263038Sbapt PKG_CONFIG_LIST, 127263038Sbapt "REPOS_DIR", 128263038Sbapt NULL, 129263038Sbapt NULL, 130263038Sbapt NULL, 131263038Sbapt false, 132263623Sbdrewery true, 133263038Sbapt }, 134287873Sdelphij [PUBKEY] = { 135287873Sdelphij PKG_CONFIG_STRING, 136287873Sdelphij "PUBKEY", 137287873Sdelphij NULL, 138287873Sdelphij NULL, 139287873Sdelphij NULL, 140287873Sdelphij false, 141287873Sdelphij false 142287873Sdelphij } 143247841Sbapt}; 144247841Sbapt 145247841Sbaptstatic const char * 146247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e) 147247841Sbapt{ 148247841Sbapt int i; 149247841Sbapt 150247841Sbapt for (i = 0; m[i].string != NULL; i++) 151247841Sbapt if (m[i].elf_nb == e) 152247841Sbapt return (m[i].string); 153247841Sbapt 154247841Sbapt return ("unknown"); 155247841Sbapt} 156247841Sbapt 157247841Sbaptstatic int 158247841Sbaptpkg_get_myabi(char *dest, size_t sz) 159247841Sbapt{ 160247841Sbapt Elf *elf; 161247841Sbapt Elf_Data *data; 162247841Sbapt Elf_Note note; 163247841Sbapt Elf_Scn *scn; 164247841Sbapt char *src, *osname; 165247841Sbapt const char *abi; 166247841Sbapt GElf_Ehdr elfhdr; 167247841Sbapt GElf_Shdr shdr; 168247841Sbapt int fd, i, ret; 169247841Sbapt uint32_t version; 170247841Sbapt 171247841Sbapt version = 0; 172247841Sbapt ret = -1; 173247841Sbapt scn = NULL; 174247841Sbapt abi = NULL; 175247841Sbapt 176247841Sbapt if (elf_version(EV_CURRENT) == EV_NONE) { 177247841Sbapt warnx("ELF library initialization failed: %s", 178247841Sbapt elf_errmsg(-1)); 179247841Sbapt return (-1); 180247841Sbapt } 181247841Sbapt 182247841Sbapt if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 183247841Sbapt warn("open()"); 184247841Sbapt return (-1); 185247841Sbapt } 186247841Sbapt 187247841Sbapt if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 188247841Sbapt ret = -1; 189247841Sbapt warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 190247841Sbapt goto cleanup; 191247841Sbapt } 192247841Sbapt 193247841Sbapt if (gelf_getehdr(elf, &elfhdr) == NULL) { 194247841Sbapt ret = -1; 195247841Sbapt warn("getehdr() failed: %s.", elf_errmsg(-1)); 196247841Sbapt goto cleanup; 197247841Sbapt } 198247841Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 199247841Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 200247841Sbapt ret = -1; 201247841Sbapt warn("getshdr() failed: %s.", elf_errmsg(-1)); 202247841Sbapt goto cleanup; 203247841Sbapt } 204247841Sbapt 205247841Sbapt if (shdr.sh_type == SHT_NOTE) 206247841Sbapt break; 207247841Sbapt } 208247841Sbapt 209247841Sbapt if (scn == NULL) { 210247841Sbapt ret = -1; 211247841Sbapt warn("failed to get the note section"); 212247841Sbapt goto cleanup; 213247841Sbapt } 214247841Sbapt 215247841Sbapt data = elf_getdata(scn, NULL); 216247841Sbapt src = data->d_buf; 217247841Sbapt for (;;) { 218247841Sbapt memcpy(¬e, src, sizeof(Elf_Note)); 219247841Sbapt src += sizeof(Elf_Note); 220247841Sbapt if (note.n_type == NT_VERSION) 221247841Sbapt break; 222247841Sbapt src += note.n_namesz + note.n_descsz; 223247841Sbapt } 224247841Sbapt osname = src; 225247841Sbapt src += roundup2(note.n_namesz, 4); 226247841Sbapt if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 227247841Sbapt version = be32dec(src); 228247841Sbapt else 229247841Sbapt version = le32dec(src); 230247841Sbapt 231247841Sbapt for (i = 0; osname[i] != '\0'; i++) 232247841Sbapt osname[i] = (char)tolower(osname[i]); 233247841Sbapt 234247841Sbapt snprintf(dest, sz, "%s:%d:%s:%s", 235247841Sbapt osname, version / 100000, 236247841Sbapt elf_corres_to_string(mach_corres, (int)elfhdr.e_machine), 237247841Sbapt elf_corres_to_string(wordsize_corres, 238247841Sbapt (int)elfhdr.e_ident[EI_CLASS])); 239247841Sbapt 240247841Sbapt ret = 0; 241247841Sbapt 242247841Sbapt switch (elfhdr.e_machine) { 243247841Sbapt case EM_ARM: 244247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 245247841Sbapt ":%s:%s:%s", elf_corres_to_string(endian_corres, 246247841Sbapt (int)elfhdr.e_ident[EI_DATA]), 247247841Sbapt (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ? 248247841Sbapt "eabi" : "oabi", 249247841Sbapt (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ? 250247841Sbapt "softfp" : "vfp"); 251247841Sbapt break; 252247841Sbapt case EM_MIPS: 253247841Sbapt /* 254247841Sbapt * this is taken from binutils sources: 255247841Sbapt * include/elf/mips.h 256247841Sbapt * mapping is figured out from binutils: 257247841Sbapt * gas/config/tc-mips.c 258247841Sbapt */ 259247841Sbapt switch (elfhdr.e_flags & EF_MIPS_ABI) { 260247841Sbapt case E_MIPS_ABI_O32: 261247841Sbapt abi = "o32"; 262247841Sbapt break; 263247841Sbapt case E_MIPS_ABI_N32: 264247841Sbapt abi = "n32"; 265247841Sbapt break; 266247841Sbapt default: 267247841Sbapt if (elfhdr.e_ident[EI_DATA] == 268247841Sbapt ELFCLASS32) 269247841Sbapt abi = "o32"; 270247841Sbapt else if (elfhdr.e_ident[EI_DATA] == 271247841Sbapt ELFCLASS64) 272247841Sbapt abi = "n64"; 273247841Sbapt break; 274247841Sbapt } 275247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 276247841Sbapt ":%s:%s", elf_corres_to_string(endian_corres, 277247841Sbapt (int)elfhdr.e_ident[EI_DATA]), abi); 278247841Sbapt break; 279247841Sbapt } 280247841Sbapt 281247841Sbaptcleanup: 282247841Sbapt if (elf != NULL) 283247841Sbapt elf_end(elf); 284247841Sbapt 285247841Sbapt close(fd); 286247841Sbapt return (ret); 287247841Sbapt} 288247841Sbapt 289247841Sbaptstatic void 290247841Sbaptsubst_packagesite(const char *abi) 291247841Sbapt{ 292247841Sbapt struct sbuf *newval; 293247841Sbapt const char *variable_string; 294247841Sbapt const char *oldval; 295247841Sbapt 296247841Sbapt if (c[PACKAGESITE].value != NULL) 297247841Sbapt oldval = c[PACKAGESITE].value; 298247841Sbapt else 299247841Sbapt oldval = c[PACKAGESITE].val; 300247841Sbapt 301247841Sbapt if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 302247841Sbapt return; 303247841Sbapt 304247841Sbapt newval = sbuf_new_auto(); 305247841Sbapt sbuf_bcat(newval, oldval, variable_string - oldval); 306247841Sbapt sbuf_cat(newval, abi); 307247841Sbapt sbuf_cat(newval, variable_string + strlen("${ABI}")); 308247841Sbapt sbuf_finish(newval); 309247841Sbapt 310247841Sbapt free(c[PACKAGESITE].value); 311247841Sbapt c[PACKAGESITE].value = strdup(sbuf_data(newval)); 312247841Sbapt} 313247841Sbapt 314263038Sbaptstatic int 315263038Sbaptboolstr_to_bool(const char *str) 316263038Sbapt{ 317263038Sbapt if (str != NULL && (strcasecmp(str, "true") == 0 || 318263038Sbapt strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 319263038Sbapt str[0] == '1')) 320263038Sbapt return (true); 321263038Sbapt 322263038Sbapt return (false); 323263038Sbapt} 324263038Sbapt 325247841Sbaptstatic void 326263038Sbaptconfig_parse(ucl_object_t *obj, pkg_conf_file_t conftype) 327247841Sbapt{ 328247841Sbapt struct sbuf *buf = sbuf_new_auto(); 329263038Sbapt ucl_object_t *cur, *seq; 330263038Sbapt ucl_object_iter_t it = NULL, itseq = NULL; 331263038Sbapt struct config_entry *temp_config; 332263038Sbapt struct config_value *cv; 333263038Sbapt const char *key; 334247841Sbapt int i; 335247841Sbapt size_t j; 336247841Sbapt 337263038Sbapt /* Temporary config for configs that may be disabled. */ 338263038Sbapt temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 339247841Sbapt 340263038Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 341263038Sbapt key = ucl_object_key(cur); 342263038Sbapt if (key == NULL) 343247841Sbapt continue; 344263038Sbapt sbuf_clear(buf); 345247841Sbapt 346263038Sbapt if (conftype == CONFFILE_PKG) { 347263038Sbapt for (j = 0; j < strlen(key); ++j) 348263038Sbapt sbuf_putc(buf, key[j]); 349263038Sbapt sbuf_finish(buf); 350263038Sbapt } else if (conftype == CONFFILE_REPO) { 351263038Sbapt if (strcasecmp(key, "url") == 0) 352263038Sbapt sbuf_cpy(buf, "PACKAGESITE"); 353263038Sbapt else if (strcasecmp(key, "mirror_type") == 0) 354263038Sbapt sbuf_cpy(buf, "MIRROR_TYPE"); 355263038Sbapt else if (strcasecmp(key, "signature_type") == 0) 356263038Sbapt sbuf_cpy(buf, "SIGNATURE_TYPE"); 357263038Sbapt else if (strcasecmp(key, "fingerprints") == 0) 358263038Sbapt sbuf_cpy(buf, "FINGERPRINTS"); 359287873Sdelphij else if (strcasecmp(key, "pubkey") == 0) 360287873Sdelphij sbuf_cpy(buf, "PUBKEY"); 361263038Sbapt else if (strcasecmp(key, "enabled") == 0) { 362263038Sbapt if ((cur->type != UCL_BOOLEAN) || 363263038Sbapt !ucl_object_toboolean(cur)) 364263038Sbapt goto cleanup; 365263038Sbapt } else 366263038Sbapt continue; 367263038Sbapt sbuf_finish(buf); 368247841Sbapt } 369247841Sbapt 370247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 371247841Sbapt if (strcmp(sbuf_data(buf), c[i].key) == 0) 372247841Sbapt break; 373247841Sbapt } 374247841Sbapt 375263038Sbapt /* Silently skip unknown keys to be future compatible. */ 376263038Sbapt if (i == CONFIG_SIZE) 377247841Sbapt continue; 378247841Sbapt 379247841Sbapt /* env has priority over config file */ 380263038Sbapt if (c[i].envset) 381247841Sbapt continue; 382263038Sbapt 383263038Sbapt /* Parse sequence value ["item1", "item2"] */ 384263038Sbapt switch (c[i].type) { 385263038Sbapt case PKG_CONFIG_LIST: 386263038Sbapt if (cur->type != UCL_ARRAY) { 387263038Sbapt warnx("Skipping invalid array " 388263038Sbapt "value for %s.\n", c[i].key); 389263038Sbapt continue; 390263038Sbapt } 391263038Sbapt temp_config[i].list = 392263038Sbapt malloc(sizeof(*temp_config[i].list)); 393263038Sbapt STAILQ_INIT(temp_config[i].list); 394263038Sbapt 395263038Sbapt while ((seq = ucl_iterate_object(cur, &itseq, true))) { 396263038Sbapt if (seq->type != UCL_STRING) 397263038Sbapt continue; 398263038Sbapt cv = malloc(sizeof(struct config_value)); 399263038Sbapt cv->value = 400263038Sbapt strdup(ucl_object_tostring(seq)); 401263038Sbapt STAILQ_INSERT_TAIL(temp_config[i].list, cv, 402263038Sbapt next); 403263038Sbapt } 404263038Sbapt break; 405263627Sbdrewery case PKG_CONFIG_BOOL: 406263627Sbdrewery temp_config[i].value = 407263627Sbdrewery strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 408263627Sbdrewery break; 409263038Sbapt default: 410263038Sbapt /* Normal string value. */ 411263038Sbapt temp_config[i].value = strdup(ucl_object_tostring(cur)); 412263038Sbapt break; 413247841Sbapt } 414263038Sbapt } 415247841Sbapt 416263038Sbapt /* Repo is enabled, copy over all settings from temp_config. */ 417263038Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 418263038Sbapt if (c[i].envset) 419263038Sbapt continue; 420263623Sbdrewery /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 421263623Sbdrewery if (conftype != CONFFILE_PKG && c[i].main_only == true) 422263623Sbdrewery continue; 423263038Sbapt switch (c[i].type) { 424263038Sbapt case PKG_CONFIG_LIST: 425263038Sbapt c[i].list = temp_config[i].list; 426263038Sbapt break; 427263038Sbapt default: 428263038Sbapt c[i].value = temp_config[i].value; 429263038Sbapt break; 430263038Sbapt } 431247841Sbapt } 432247841Sbapt 433263038Sbaptcleanup: 434263038Sbapt free(temp_config); 435247841Sbapt sbuf_delete(buf); 436247841Sbapt} 437247841Sbapt 438263038Sbapt/*- 439263038Sbapt * Parse new repo style configs in style: 440263038Sbapt * Name: 441263038Sbapt * URL: 442263038Sbapt * MIRROR_TYPE: 443263038Sbapt * etc... 444263038Sbapt */ 445263038Sbaptstatic void 446263038Sbaptparse_repo_file(ucl_object_t *obj) 447263038Sbapt{ 448263038Sbapt ucl_object_iter_t it = NULL; 449263038Sbapt ucl_object_t *cur; 450263038Sbapt const char *key; 451263038Sbapt 452263038Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 453263038Sbapt key = ucl_object_key(cur); 454263038Sbapt 455263038Sbapt if (key == NULL) 456263038Sbapt continue; 457263038Sbapt 458263038Sbapt if (cur->type != UCL_OBJECT) 459263038Sbapt continue; 460263038Sbapt 461263038Sbapt config_parse(cur, CONFFILE_REPO); 462263038Sbapt } 463263038Sbapt} 464263038Sbapt 465263038Sbapt 466263038Sbaptstatic int 467263038Sbaptread_conf_file(const char *confpath, pkg_conf_file_t conftype) 468263038Sbapt{ 469263038Sbapt struct ucl_parser *p; 470263038Sbapt ucl_object_t *obj = NULL; 471263038Sbapt 472263038Sbapt p = ucl_parser_new(0); 473263038Sbapt 474263038Sbapt if (!ucl_parser_add_file(p, confpath)) { 475263038Sbapt if (errno != ENOENT) 476263038Sbapt errx(EXIT_FAILURE, "Unable to parse configuration " 477263038Sbapt "file %s: %s", confpath, ucl_parser_get_error(p)); 478263038Sbapt ucl_parser_free(p); 479263038Sbapt /* no configuration present */ 480263038Sbapt return (1); 481263038Sbapt } 482263038Sbapt 483263038Sbapt obj = ucl_parser_get_object(p); 484263038Sbapt if (obj->type != UCL_OBJECT) 485263038Sbapt warnx("Invalid configuration format, ignoring the " 486263038Sbapt "configuration file %s", confpath); 487263038Sbapt else { 488263038Sbapt if (conftype == CONFFILE_PKG) 489263038Sbapt config_parse(obj, conftype); 490263038Sbapt else if (conftype == CONFFILE_REPO) 491263038Sbapt parse_repo_file(obj); 492263038Sbapt } 493263038Sbapt 494263038Sbapt ucl_object_free(obj); 495263038Sbapt ucl_parser_free(p); 496263038Sbapt 497263038Sbapt return (0); 498263038Sbapt} 499263038Sbapt 500263038Sbaptstatic int 501263038Sbaptload_repositories(const char *repodir) 502263038Sbapt{ 503263038Sbapt struct dirent *ent; 504263038Sbapt DIR *d; 505263038Sbapt char *p; 506263038Sbapt size_t n; 507263038Sbapt char path[MAXPATHLEN]; 508263038Sbapt int ret; 509263038Sbapt 510263038Sbapt ret = 0; 511263038Sbapt 512263038Sbapt if ((d = opendir(repodir)) == NULL) 513263038Sbapt return (1); 514263038Sbapt 515263038Sbapt while ((ent = readdir(d))) { 516263038Sbapt /* Trim out 'repos'. */ 517263038Sbapt if ((n = strlen(ent->d_name)) <= 5) 518263038Sbapt continue; 519263038Sbapt p = &ent->d_name[n - 5]; 520263038Sbapt if (strcmp(p, ".conf") == 0) { 521263038Sbapt snprintf(path, sizeof(path), "%s%s%s", 522263038Sbapt repodir, 523263038Sbapt repodir[strlen(repodir) - 1] == '/' ? "" : "/", 524263038Sbapt ent->d_name); 525263038Sbapt if (access(path, F_OK) == 0 && 526263038Sbapt read_conf_file(path, CONFFILE_REPO)) { 527263038Sbapt ret = 1; 528263038Sbapt goto cleanup; 529263038Sbapt } 530263038Sbapt } 531263038Sbapt } 532263038Sbapt 533263038Sbaptcleanup: 534263038Sbapt closedir(d); 535263038Sbapt 536263038Sbapt return (ret); 537263038Sbapt} 538263038Sbapt 539247841Sbaptint 540247841Sbaptconfig_init(void) 541247841Sbapt{ 542263038Sbapt char *val; 543247841Sbapt int i; 544247841Sbapt const char *localbase; 545263038Sbapt char *env_list_item; 546247841Sbapt char confpath[MAXPATHLEN]; 547263038Sbapt struct config_value *cv; 548247841Sbapt char abi[BUFSIZ]; 549247841Sbapt 550247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 551247841Sbapt val = getenv(c[i].key); 552247841Sbapt if (val != NULL) { 553247841Sbapt c[i].envset = true; 554263038Sbapt switch (c[i].type) { 555263038Sbapt case PKG_CONFIG_LIST: 556263038Sbapt /* Split up comma-separated items from env. */ 557263038Sbapt c[i].list = malloc(sizeof(*c[i].list)); 558263038Sbapt STAILQ_INIT(c[i].list); 559263038Sbapt for (env_list_item = strtok(val, ","); 560263038Sbapt env_list_item != NULL; 561263038Sbapt env_list_item = strtok(NULL, ",")) { 562263038Sbapt cv = 563263038Sbapt malloc(sizeof(struct config_value)); 564263038Sbapt cv->value = 565263038Sbapt strdup(env_list_item); 566263038Sbapt STAILQ_INSERT_TAIL(c[i].list, cv, 567263038Sbapt next); 568263038Sbapt } 569263038Sbapt break; 570263038Sbapt default: 571263038Sbapt c[i].val = val; 572263038Sbapt break; 573263038Sbapt } 574247841Sbapt } 575247841Sbapt } 576247841Sbapt 577263038Sbapt /* Read LOCALBASE/etc/pkg.conf first. */ 578247841Sbapt localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 579263038Sbapt snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 580263038Sbapt localbase); 581247841Sbapt 582263038Sbapt if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 583263038Sbapt CONFFILE_PKG)) 584247841Sbapt goto finalize; 585247841Sbapt 586263038Sbapt /* Then read in all repos from REPOS_DIR list of directories. */ 587263038Sbapt if (c[REPOS_DIR].list == NULL) { 588263038Sbapt c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 589263038Sbapt STAILQ_INIT(c[REPOS_DIR].list); 590263038Sbapt cv = malloc(sizeof(struct config_value)); 591263038Sbapt cv->value = strdup("/etc/pkg"); 592263038Sbapt STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 593263038Sbapt cv = malloc(sizeof(struct config_value)); 594263038Sbapt if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 595263038Sbapt goto finalize; 596263038Sbapt STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 597247841Sbapt } 598247841Sbapt 599263038Sbapt STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 600263038Sbapt if (load_repositories(cv->value)) 601263038Sbapt goto finalize; 602247841Sbapt 603247841Sbaptfinalize: 604247841Sbapt if (c[ABI].val == NULL && c[ABI].value == NULL) { 605247841Sbapt if (pkg_get_myabi(abi, BUFSIZ) != 0) 606263038Sbapt errx(EXIT_FAILURE, "Failed to determine the system " 607263038Sbapt "ABI"); 608247841Sbapt c[ABI].val = abi; 609247841Sbapt } 610247841Sbapt 611247841Sbapt subst_packagesite(c[ABI].val); 612247841Sbapt 613247841Sbapt return (0); 614247841Sbapt} 615247841Sbapt 616247841Sbaptint 617247841Sbaptconfig_string(pkg_config_key k, const char **val) 618247841Sbapt{ 619247841Sbapt if (c[k].type != PKG_CONFIG_STRING) 620247841Sbapt return (-1); 621247841Sbapt 622247841Sbapt if (c[k].value != NULL) 623247841Sbapt *val = c[k].value; 624247841Sbapt else 625247841Sbapt *val = c[k].val; 626247841Sbapt 627247841Sbapt return (0); 628247841Sbapt} 629247841Sbapt 630247841Sbaptint 631247841Sbaptconfig_bool(pkg_config_key k, bool *val) 632247841Sbapt{ 633247841Sbapt const char *value; 634247841Sbapt 635247841Sbapt if (c[k].type != PKG_CONFIG_BOOL) 636247841Sbapt return (-1); 637247841Sbapt 638247841Sbapt *val = false; 639247841Sbapt 640247841Sbapt if (c[k].value != NULL) 641247841Sbapt value = c[k].value; 642247841Sbapt else 643247841Sbapt value = c[k].val; 644247841Sbapt 645263038Sbapt if (boolstr_to_bool(value)) 646247841Sbapt *val = true; 647247841Sbapt 648247841Sbapt return (0); 649247841Sbapt} 650247841Sbapt 651247841Sbaptvoid 652247841Sbaptconfig_finish(void) { 653247841Sbapt int i; 654247841Sbapt 655247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) 656247841Sbapt free(c[i].value); 657247841Sbapt} 658