config.c revision 257145
1247841Sbapt/*- 2247841Sbapt * Copyright (c) 2013 Baptiste Daroussin <bapt@FreeBSD.org> 3247841Sbapt * All rights reserved. 4247841Sbapt * 5247841Sbapt * Redistribution and use in source and binary forms, with or without 6247841Sbapt * modification, are permitted provided that the following conditions 7247841Sbapt * are met: 8247841Sbapt * 1. Redistributions of source code must retain the above copyright 9247841Sbapt * notice, this list of conditions and the following disclaimer. 10247841Sbapt * 2. Redistributions in binary form must reproduce the above copyright 11247841Sbapt * notice, this list of conditions and the following disclaimer in the 12247841Sbapt * documentation and/or other materials provided with the distribution. 13247841Sbapt * 14247841Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15247841Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16247841Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17247841Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18247841Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19247841Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20247841Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21247841Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22247841Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23247841Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24247841Sbapt * SUCH DAMAGE. 25247841Sbapt */ 26247841Sbapt 27247841Sbapt#include <sys/cdefs.h> 28247841Sbapt__FBSDID("$FreeBSD: head/usr.sbin/pkg/config.c 257145 2013-10-26 03:31:05Z bdrewery $"); 29247841Sbapt 30247841Sbapt#include <sys/param.h> 31247841Sbapt#include <sys/sbuf.h> 32247841Sbapt#include <sys/elf_common.h> 33247841Sbapt#include <sys/endian.h> 34247841Sbapt 35255457Sbapt#include <assert.h> 36256450Sbdrewery#include <yaml.h> 37247841Sbapt#include <ctype.h> 38247841Sbapt#include <err.h> 39247841Sbapt#include <errno.h> 40247841Sbapt#include <fcntl.h> 41247841Sbapt#include <gelf.h> 42247841Sbapt#include <inttypes.h> 43247841Sbapt#include <paths.h> 44247841Sbapt#include <stdbool.h> 45247841Sbapt#include <string.h> 46247841Sbapt#include <unistd.h> 47247841Sbapt 48247841Sbapt#include "elf_tables.h" 49247841Sbapt#include "config.h" 50247841Sbapt 51247841Sbapt#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 52247841Sbapt 53247841Sbaptstruct config_entry { 54247841Sbapt uint8_t type; 55247841Sbapt const char *key; 56247841Sbapt const char *val; 57247841Sbapt char *value; 58247841Sbapt bool envset; 59247841Sbapt}; 60247841Sbapt 61247841Sbaptstatic struct config_entry c[] = { 62247841Sbapt [PACKAGESITE] = { 63247841Sbapt PKG_CONFIG_STRING, 64247841Sbapt "PACKAGESITE", 65257051Sbdrewery URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 66247841Sbapt NULL, 67247841Sbapt false, 68247841Sbapt }, 69247841Sbapt [ABI] = { 70247841Sbapt PKG_CONFIG_STRING, 71247841Sbapt "ABI", 72247841Sbapt NULL, 73247841Sbapt NULL, 74247841Sbapt false, 75247841Sbapt }, 76247841Sbapt [MIRROR_TYPE] = { 77247841Sbapt PKG_CONFIG_STRING, 78247841Sbapt "MIRROR_TYPE", 79247841Sbapt "SRV", 80247841Sbapt NULL, 81247841Sbapt false, 82247841Sbapt }, 83247841Sbapt [ASSUME_ALWAYS_YES] = { 84247841Sbapt PKG_CONFIG_BOOL, 85247841Sbapt "ASSUME_ALWAYS_YES", 86247841Sbapt "NO", 87247841Sbapt NULL, 88247841Sbapt false, 89247841Sbapt } 90247841Sbapt}; 91247841Sbapt 92247841Sbaptstatic const char * 93247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e) 94247841Sbapt{ 95247841Sbapt int i; 96247841Sbapt 97247841Sbapt for (i = 0; m[i].string != NULL; i++) 98247841Sbapt if (m[i].elf_nb == e) 99247841Sbapt return (m[i].string); 100247841Sbapt 101247841Sbapt return ("unknown"); 102247841Sbapt} 103247841Sbapt 104255457Sbaptstatic const char * 105255457Sbaptaeabi_parse_arm_attributes(void *data, size_t length) 106255457Sbapt{ 107255457Sbapt uint32_t sect_len; 108255457Sbapt uint8_t *section = data; 109255457Sbapt 110255457Sbapt#define MOVE(len) do { \ 111255457Sbapt assert(length >= (len)); \ 112255457Sbapt section += (len); \ 113255457Sbapt length -= (len); \ 114255457Sbapt} while (0) 115255457Sbapt 116255457Sbapt if (length == 0 || *section != 'A') 117255457Sbapt return (NULL); 118255457Sbapt 119255457Sbapt MOVE(1); 120255457Sbapt 121255457Sbapt /* Read the section length */ 122255457Sbapt if (length < sizeof(sect_len)) 123255457Sbapt return (NULL); 124255457Sbapt 125255457Sbapt memcpy(§_len, section, sizeof(sect_len)); 126255457Sbapt 127255457Sbapt /* 128255457Sbapt * The section length should be no longer than the section it is within 129255457Sbapt */ 130255457Sbapt if (sect_len > length) 131255457Sbapt return (NULL); 132255457Sbapt 133255457Sbapt MOVE(sizeof(sect_len)); 134255457Sbapt 135255457Sbapt /* Skip the vendor name */ 136255457Sbapt while (length != 0) { 137255457Sbapt if (*section == '\0') 138255457Sbapt break; 139255457Sbapt MOVE(1); 140255457Sbapt } 141255457Sbapt if (length == 0) 142255457Sbapt return (NULL); 143255457Sbapt MOVE(1); 144255457Sbapt 145255457Sbapt while (length != 0) { 146255457Sbapt uint32_t tag_length; 147255457Sbapt 148255457Sbapt switch(*section) { 149255457Sbapt case 1: /* Tag_File */ 150255457Sbapt MOVE(1); 151255457Sbapt if (length < sizeof(tag_length)) 152255457Sbapt return (NULL); 153255457Sbapt memcpy(&tag_length, section, sizeof(tag_length)); 154255457Sbapt break; 155255457Sbapt case 2: /* Tag_Section */ 156255457Sbapt case 3: /* Tag_Symbol */ 157255457Sbapt default: 158255457Sbapt return (NULL); 159255457Sbapt } 160255457Sbapt /* At least space for the tag and size */ 161255457Sbapt if (tag_length <= 5) 162255457Sbapt return (NULL); 163255457Sbapt tag_length--; 164255457Sbapt /* Check the tag fits */ 165255457Sbapt if (tag_length > length) 166255457Sbapt return (NULL); 167255457Sbapt 168255457Sbapt#define MOVE_TAG(len) do { \ 169255457Sbapt assert(tag_length >= (len)); \ 170255457Sbapt MOVE(len); \ 171255457Sbapt tag_length -= (len); \ 172255457Sbapt} while(0) 173255457Sbapt 174255457Sbapt MOVE(sizeof(tag_length)); 175255457Sbapt tag_length -= sizeof(tag_length); 176255457Sbapt 177255457Sbapt while (tag_length != 0) { 178255457Sbapt uint8_t tag; 179255457Sbapt 180255457Sbapt assert(tag_length >= length); 181255457Sbapt 182255457Sbapt tag = *section; 183255457Sbapt MOVE_TAG(1); 184255457Sbapt 185255457Sbapt /* 186255457Sbapt * These tag values come from: 187255457Sbapt * 188255457Sbapt * Addenda to, and Errata in, the ABI for the 189255457Sbapt * ARM Architecture. Release 2.08, section 2.3. 190255457Sbapt */ 191255457Sbapt if (tag == 6) { /* == Tag_CPU_arch */ 192255457Sbapt uint8_t val; 193255457Sbapt 194255457Sbapt val = *section; 195255457Sbapt /* 196255457Sbapt * We don't support values that require 197255457Sbapt * more than one byte. 198255457Sbapt */ 199255457Sbapt if (val & (1 << 7)) 200255457Sbapt return (NULL); 201255457Sbapt 202255457Sbapt /* We have an ARMv4 or ARMv5 */ 203255457Sbapt if (val <= 5) 204255457Sbapt return ("arm"); 205255457Sbapt else /* We have an ARMv6+ */ 206255457Sbapt return ("armv6"); 207255457Sbapt } else if (tag == 4 || tag == 5 || tag == 32 || 208255457Sbapt tag == 65 || tag == 67) { 209255457Sbapt while (*section != '\0' && length != 0) 210255457Sbapt MOVE_TAG(1); 211255457Sbapt if (tag_length == 0) 212255457Sbapt return (NULL); 213255457Sbapt /* Skip the last byte */ 214255457Sbapt MOVE_TAG(1); 215255457Sbapt } else if ((tag >= 7 && tag <= 31) || tag == 34 || 216255457Sbapt tag == 36 || tag == 38 || tag == 42 || tag == 44 || 217255457Sbapt tag == 64 || tag == 66 || tag == 68 || tag == 70) { 218255457Sbapt /* Skip the uleb128 data */ 219255457Sbapt while (*section & (1 << 7) && length != 0) 220255457Sbapt MOVE_TAG(1); 221255457Sbapt if (tag_length == 0) 222255457Sbapt return (NULL); 223255457Sbapt /* Skip the last byte */ 224255457Sbapt MOVE_TAG(1); 225255457Sbapt } else 226255457Sbapt return (NULL); 227255457Sbapt#undef MOVE_TAG 228255457Sbapt } 229255457Sbapt 230255457Sbapt break; 231255457Sbapt } 232255457Sbapt return (NULL); 233255457Sbapt#undef MOVE 234255457Sbapt} 235255457Sbapt 236247841Sbaptstatic int 237247841Sbaptpkg_get_myabi(char *dest, size_t sz) 238247841Sbapt{ 239247841Sbapt Elf *elf; 240247841Sbapt Elf_Data *data; 241247841Sbapt Elf_Note note; 242247841Sbapt Elf_Scn *scn; 243247841Sbapt char *src, *osname; 244255457Sbapt const char *arch, *abi, *fpu, *endian_corres_str; 245255457Sbapt const char *wordsize_corres_str; 246247841Sbapt GElf_Ehdr elfhdr; 247247841Sbapt GElf_Shdr shdr; 248247841Sbapt int fd, i, ret; 249247841Sbapt uint32_t version; 250247841Sbapt 251247841Sbapt version = 0; 252247841Sbapt ret = -1; 253247841Sbapt scn = NULL; 254247841Sbapt abi = NULL; 255247841Sbapt 256247841Sbapt if (elf_version(EV_CURRENT) == EV_NONE) { 257247841Sbapt warnx("ELF library initialization failed: %s", 258247841Sbapt elf_errmsg(-1)); 259247841Sbapt return (-1); 260247841Sbapt } 261247841Sbapt 262247841Sbapt if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 263247841Sbapt warn("open()"); 264247841Sbapt return (-1); 265247841Sbapt } 266247841Sbapt 267247841Sbapt if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 268247841Sbapt ret = -1; 269247841Sbapt warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 270247841Sbapt goto cleanup; 271247841Sbapt } 272247841Sbapt 273247841Sbapt if (gelf_getehdr(elf, &elfhdr) == NULL) { 274247841Sbapt ret = -1; 275247841Sbapt warn("getehdr() failed: %s.", elf_errmsg(-1)); 276247841Sbapt goto cleanup; 277247841Sbapt } 278247841Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 279247841Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 280247841Sbapt ret = -1; 281247841Sbapt warn("getshdr() failed: %s.", elf_errmsg(-1)); 282247841Sbapt goto cleanup; 283247841Sbapt } 284247841Sbapt 285247841Sbapt if (shdr.sh_type == SHT_NOTE) 286247841Sbapt break; 287247841Sbapt } 288247841Sbapt 289247841Sbapt if (scn == NULL) { 290247841Sbapt ret = -1; 291247841Sbapt warn("failed to get the note section"); 292247841Sbapt goto cleanup; 293247841Sbapt } 294247841Sbapt 295247841Sbapt data = elf_getdata(scn, NULL); 296247841Sbapt src = data->d_buf; 297247841Sbapt for (;;) { 298247841Sbapt memcpy(¬e, src, sizeof(Elf_Note)); 299247841Sbapt src += sizeof(Elf_Note); 300247841Sbapt if (note.n_type == NT_VERSION) 301247841Sbapt break; 302247841Sbapt src += note.n_namesz + note.n_descsz; 303247841Sbapt } 304247841Sbapt osname = src; 305247841Sbapt src += roundup2(note.n_namesz, 4); 306247841Sbapt if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 307247841Sbapt version = be32dec(src); 308247841Sbapt else 309247841Sbapt version = le32dec(src); 310247841Sbapt 311247841Sbapt for (i = 0; osname[i] != '\0'; i++) 312247841Sbapt osname[i] = (char)tolower(osname[i]); 313247841Sbapt 314255457Sbapt wordsize_corres_str = elf_corres_to_string(wordsize_corres, 315255457Sbapt (int)elfhdr.e_ident[EI_CLASS]); 316247841Sbapt 317255457Sbapt arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 318255457Sbapt 319255457Sbapt snprintf(dest, sz, "%s:%d", 320255457Sbapt osname, version / 100000); 321255457Sbapt 322247841Sbapt ret = 0; 323247841Sbapt 324247841Sbapt switch (elfhdr.e_machine) { 325247841Sbapt case EM_ARM: 326255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 327255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 328255457Sbapt 329253755Sbapt /* FreeBSD doesn't support the hard-float ABI yet */ 330253755Sbapt fpu = "softfp"; 331253755Sbapt if ((elfhdr.e_flags & 0xFF000000) != 0) { 332255457Sbapt const char *sh_name = NULL; 333255457Sbapt size_t shstrndx; 334255457Sbapt 335253755Sbapt /* This is an EABI file, the conformance level is set */ 336253755Sbapt abi = "eabi"; 337255457Sbapt /* Find which TARGET_ARCH we are building for. */ 338255457Sbapt elf_getshdrstrndx(elf, &shstrndx); 339255457Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 340255457Sbapt sh_name = NULL; 341255457Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 342255457Sbapt scn = NULL; 343255457Sbapt break; 344255457Sbapt } 345255457Sbapt 346255457Sbapt sh_name = elf_strptr(elf, shstrndx, 347255457Sbapt shdr.sh_name); 348255457Sbapt if (sh_name == NULL) 349255457Sbapt continue; 350255457Sbapt if (strcmp(".ARM.attributes", sh_name) == 0) 351255457Sbapt break; 352255457Sbapt } 353255457Sbapt if (scn != NULL && sh_name != NULL) { 354255457Sbapt data = elf_getdata(scn, NULL); 355255457Sbapt /* 356255457Sbapt * Prior to FreeBSD 10.0 libelf would return 357255457Sbapt * NULL from elf_getdata on the .ARM.attributes 358255457Sbapt * section. As this was the first release to 359255457Sbapt * get armv6 support assume a NULL value means 360255457Sbapt * arm. 361255457Sbapt * 362255457Sbapt * This assumption can be removed when 9.x 363255457Sbapt * is unsupported. 364255457Sbapt */ 365255457Sbapt if (data != NULL) { 366255457Sbapt arch = aeabi_parse_arm_attributes( 367255457Sbapt data->d_buf, data->d_size); 368255457Sbapt if (arch == NULL) { 369255457Sbapt ret = 1; 370255457Sbapt warn("unknown ARM ARCH"); 371255457Sbapt goto cleanup; 372255457Sbapt } 373255457Sbapt } 374255457Sbapt } else { 375255457Sbapt ret = 1; 376255457Sbapt warn("Unable to find the .ARM.attributes " 377255457Sbapt "section"); 378255457Sbapt goto cleanup; 379255457Sbapt } 380253755Sbapt } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 381253755Sbapt /* 382253755Sbapt * EABI executables all have this field set to 383253755Sbapt * ELFOSABI_NONE, therefore it must be an oabi file. 384253755Sbapt */ 385253755Sbapt abi = "oabi"; 386253755Sbapt } else { 387253755Sbapt ret = 1; 388255457Sbapt warn("unknown ARM ABI"); 389253755Sbapt goto cleanup; 390253755Sbapt } 391247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 392255457Sbapt ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 393255457Sbapt endian_corres_str, abi, fpu); 394247841Sbapt break; 395247841Sbapt case EM_MIPS: 396247841Sbapt /* 397247841Sbapt * this is taken from binutils sources: 398247841Sbapt * include/elf/mips.h 399247841Sbapt * mapping is figured out from binutils: 400247841Sbapt * gas/config/tc-mips.c 401247841Sbapt */ 402247841Sbapt switch (elfhdr.e_flags & EF_MIPS_ABI) { 403247841Sbapt case E_MIPS_ABI_O32: 404247841Sbapt abi = "o32"; 405247841Sbapt break; 406247841Sbapt case E_MIPS_ABI_N32: 407247841Sbapt abi = "n32"; 408247841Sbapt break; 409247841Sbapt default: 410247841Sbapt if (elfhdr.e_ident[EI_DATA] == 411247841Sbapt ELFCLASS32) 412247841Sbapt abi = "o32"; 413247841Sbapt else if (elfhdr.e_ident[EI_DATA] == 414247841Sbapt ELFCLASS64) 415247841Sbapt abi = "n64"; 416247841Sbapt break; 417247841Sbapt } 418255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 419255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 420255457Sbapt 421255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 422255457Sbapt arch, wordsize_corres_str, endian_corres_str, abi); 423247841Sbapt break; 424255457Sbapt default: 425255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 426255457Sbapt arch, wordsize_corres_str); 427247841Sbapt } 428247841Sbapt 429247841Sbaptcleanup: 430247841Sbapt if (elf != NULL) 431247841Sbapt elf_end(elf); 432247841Sbapt 433247841Sbapt close(fd); 434247841Sbapt return (ret); 435247841Sbapt} 436247841Sbapt 437247841Sbaptstatic void 438247841Sbaptsubst_packagesite(const char *abi) 439247841Sbapt{ 440247841Sbapt struct sbuf *newval; 441247841Sbapt const char *variable_string; 442247841Sbapt const char *oldval; 443247841Sbapt 444247841Sbapt if (c[PACKAGESITE].value != NULL) 445247841Sbapt oldval = c[PACKAGESITE].value; 446247841Sbapt else 447247841Sbapt oldval = c[PACKAGESITE].val; 448247841Sbapt 449247841Sbapt if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 450247841Sbapt return; 451247841Sbapt 452247841Sbapt newval = sbuf_new_auto(); 453247841Sbapt sbuf_bcat(newval, oldval, variable_string - oldval); 454247841Sbapt sbuf_cat(newval, abi); 455247841Sbapt sbuf_cat(newval, variable_string + strlen("${ABI}")); 456247841Sbapt sbuf_finish(newval); 457247841Sbapt 458247841Sbapt free(c[PACKAGESITE].value); 459247841Sbapt c[PACKAGESITE].value = strdup(sbuf_data(newval)); 460247841Sbapt} 461247841Sbapt 462247841Sbaptstatic void 463257145Sbdreweryconfig_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype) 464247841Sbapt{ 465247841Sbapt yaml_node_pair_t *pair; 466247841Sbapt yaml_node_t *key, *val; 467247841Sbapt struct sbuf *buf = sbuf_new_auto(); 468247841Sbapt int i; 469247841Sbapt size_t j; 470247841Sbapt 471247841Sbapt pair = node->data.mapping.pairs.start; 472247841Sbapt 473247841Sbapt while (pair < node->data.mapping.pairs.top) { 474247841Sbapt key = yaml_document_get_node(doc, pair->key); 475247841Sbapt val = yaml_document_get_node(doc, pair->value); 476247841Sbapt 477247841Sbapt /* 478247841Sbapt * ignoring silently empty keys can be empty lines 479247841Sbapt * or user mistakes 480247841Sbapt */ 481247841Sbapt if (key->data.scalar.length <= 0) { 482247841Sbapt ++pair; 483247841Sbapt continue; 484247841Sbapt } 485247841Sbapt 486247841Sbapt /* 487247841Sbapt * silently skip on purpose to allow user to leave 488247841Sbapt * empty lines without complaining 489247841Sbapt */ 490247841Sbapt if (val->type == YAML_NO_NODE || 491247841Sbapt (val->type == YAML_SCALAR_NODE && 492247841Sbapt val->data.scalar.length <= 0)) { 493247841Sbapt ++pair; 494247841Sbapt continue; 495247841Sbapt } 496247841Sbapt 497247841Sbapt sbuf_clear(buf); 498247841Sbapt 499257145Sbdrewery if (conftype == CONFFILE_PKG) { 500257145Sbdrewery for (j = 0; j < strlen(key->data.scalar.value); ++j) 501257145Sbdrewery sbuf_putc(buf, 502257145Sbdrewery toupper(key->data.scalar.value[j])); 503257145Sbdrewery sbuf_finish(buf); 504257145Sbdrewery } else if (conftype == CONFFILE_REPO) { 505257145Sbdrewery /* The CONFFILE_REPO type is more restrictive. Only 506257145Sbdrewery parse known elements. */ 507257145Sbdrewery if (strcasecmp(key->data.scalar.value, "url") == 0) 508257145Sbdrewery sbuf_cpy(buf, "PACKAGESITE"); 509257145Sbdrewery else if (strcasecmp(key->data.scalar.value, 510257145Sbdrewery "mirror_type") == 0) 511257145Sbdrewery sbuf_cpy(buf, "MIRROR_TYPE"); 512257145Sbdrewery else { /* Skip unknown entries for future use. */ 513257145Sbdrewery ++pair; 514257145Sbdrewery continue; 515257145Sbdrewery } 516257145Sbdrewery sbuf_finish(buf); 517257145Sbdrewery } 518257145Sbdrewery 519247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 520247841Sbapt if (strcmp(sbuf_data(buf), c[i].key) == 0) 521247841Sbapt break; 522247841Sbapt } 523247841Sbapt 524257145Sbdrewery /* Silently skip unknown keys to be future compatible. */ 525247841Sbapt if (i == CONFIG_SIZE) { 526247841Sbapt ++pair; 527247841Sbapt continue; 528247841Sbapt } 529247841Sbapt 530247841Sbapt /* env has priority over config file */ 531247841Sbapt if (c[i].envset) { 532247841Sbapt ++pair; 533247841Sbapt continue; 534247841Sbapt } 535247841Sbapt 536247841Sbapt c[i].value = strdup(val->data.scalar.value); 537247841Sbapt ++pair; 538247841Sbapt } 539247841Sbapt 540247841Sbapt sbuf_delete(buf); 541247841Sbapt} 542247841Sbapt 543257145Sbdrewery/*- 544257145Sbdrewery * Parse new repo style configs in style: 545257145Sbdrewery * Name: 546257145Sbdrewery * URL: 547257145Sbdrewery * MIRROR_TYPE: 548257145Sbdrewery * etc... 549257145Sbdrewery */ 550257145Sbdrewerystatic void 551257145Sbdreweryparse_repo_file(yaml_document_t *doc, yaml_node_t *node) 552247841Sbapt{ 553257145Sbdrewery yaml_node_pair_t *pair; 554257145Sbdrewery 555257145Sbdrewery pair = node->data.mapping.pairs.start; 556257145Sbdrewery while (pair < node->data.mapping.pairs.top) { 557257145Sbdrewery yaml_node_t *key = yaml_document_get_node(doc, pair->key); 558257145Sbdrewery yaml_node_t *val = yaml_document_get_node(doc, pair->value); 559257145Sbdrewery 560257145Sbdrewery if (key->data.scalar.length <= 0) { 561257145Sbdrewery ++pair; 562257145Sbdrewery continue; 563257145Sbdrewery } 564257145Sbdrewery 565257145Sbdrewery if (val->type != YAML_MAPPING_NODE) { 566257145Sbdrewery ++pair; 567257145Sbdrewery continue; 568257145Sbdrewery } 569257145Sbdrewery 570257145Sbdrewery config_parse(doc, val, CONFFILE_REPO); 571257145Sbdrewery ++pair; 572257145Sbdrewery } 573257145Sbdrewery} 574257145Sbdrewery 575257145Sbdrewery 576257145Sbdrewerystatic int 577257145Sbdreweryread_conf_file(const char *confpath, pkg_conf_file_t conftype) 578257145Sbdrewery{ 579247841Sbapt FILE *fp; 580247841Sbapt yaml_parser_t parser; 581247841Sbapt yaml_document_t doc; 582247841Sbapt yaml_node_t *node; 583247841Sbapt 584247841Sbapt if ((fp = fopen(confpath, "r")) == NULL) { 585247841Sbapt if (errno != ENOENT) 586257142Sbdrewery err(EXIT_FAILURE, "Unable to open configuration " 587257142Sbdrewery "file %s", confpath); 588247841Sbapt /* no configuration present */ 589257145Sbdrewery return (1); 590247841Sbapt } 591247841Sbapt 592247841Sbapt yaml_parser_initialize(&parser); 593247841Sbapt yaml_parser_set_input_file(&parser, fp); 594247841Sbapt yaml_parser_load(&parser, &doc); 595247841Sbapt 596247841Sbapt node = yaml_document_get_root_node(&doc); 597247841Sbapt 598257145Sbdrewery if (node == NULL || node->type != YAML_MAPPING_NODE) 599257142Sbdrewery warnx("Invalid configuration format, ignoring the " 600257145Sbdrewery "configuration file %s", confpath); 601257145Sbdrewery else { 602257145Sbdrewery if (conftype == CONFFILE_PKG) 603257145Sbdrewery config_parse(&doc, node, conftype); 604257145Sbdrewery else if (conftype == CONFFILE_REPO) 605257145Sbdrewery parse_repo_file(&doc, node); 606247841Sbapt } 607247841Sbapt 608247841Sbapt yaml_document_delete(&doc); 609247841Sbapt yaml_parser_delete(&parser); 610247841Sbapt 611257145Sbdrewery return (0); 612257145Sbdrewery} 613257145Sbdrewery 614257145Sbdreweryint 615257145Sbdreweryconfig_init(void) 616257145Sbdrewery{ 617257145Sbdrewery const char *val; 618257145Sbdrewery int i; 619257145Sbdrewery const char *localbase; 620257145Sbdrewery char confpath[MAXPATHLEN]; 621257145Sbdrewery char abi[BUFSIZ]; 622257145Sbdrewery 623257145Sbdrewery for (i = 0; i < CONFIG_SIZE; i++) { 624257145Sbdrewery val = getenv(c[i].key); 625257145Sbdrewery if (val != NULL) { 626257145Sbdrewery c[i].val = val; 627257145Sbdrewery c[i].envset = true; 628257145Sbdrewery } 629257145Sbdrewery } 630257145Sbdrewery 631257145Sbdrewery localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 632257145Sbdrewery snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 633257145Sbdrewery localbase); 634257145Sbdrewery 635257145Sbdrewery if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 636257145Sbdrewery CONFFILE_PKG)) 637257145Sbdrewery goto finalize; 638257145Sbdrewery 639257145Sbdrewery snprintf(confpath, sizeof(confpath), "/etc/pkg/FreeBSD.conf"); 640257145Sbdrewery if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 641257145Sbdrewery CONFFILE_REPO)) 642257145Sbdrewery goto finalize; 643257145Sbdrewery 644247841Sbaptfinalize: 645247841Sbapt if (c[ABI].val == NULL && c[ABI].value == NULL) { 646247841Sbapt if (pkg_get_myabi(abi, BUFSIZ) != 0) 647257142Sbdrewery errx(EXIT_FAILURE, "Failed to determine the system " 648257142Sbdrewery "ABI"); 649247841Sbapt c[ABI].val = abi; 650247841Sbapt } 651247841Sbapt 652247843Sbapt subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 653247841Sbapt 654247841Sbapt return (0); 655247841Sbapt} 656247841Sbapt 657247841Sbaptint 658247841Sbaptconfig_string(pkg_config_key k, const char **val) 659247841Sbapt{ 660247841Sbapt if (c[k].type != PKG_CONFIG_STRING) 661247841Sbapt return (-1); 662247841Sbapt 663247841Sbapt if (c[k].value != NULL) 664247841Sbapt *val = c[k].value; 665247841Sbapt else 666247841Sbapt *val = c[k].val; 667247841Sbapt 668247841Sbapt return (0); 669247841Sbapt} 670247841Sbapt 671247841Sbaptint 672247841Sbaptconfig_bool(pkg_config_key k, bool *val) 673247841Sbapt{ 674247841Sbapt const char *value; 675247841Sbapt 676247841Sbapt if (c[k].type != PKG_CONFIG_BOOL) 677247841Sbapt return (-1); 678247841Sbapt 679247841Sbapt *val = false; 680247841Sbapt 681247841Sbapt if (c[k].value != NULL) 682247841Sbapt value = c[k].value; 683247841Sbapt else 684247841Sbapt value = c[k].val; 685247841Sbapt 686247841Sbapt if (strcasecmp(value, "true") == 0 || 687247841Sbapt strcasecmp(value, "yes") == 0 || 688247841Sbapt strcasecmp(value, "on") == 0 || 689247841Sbapt *value == '1') 690247841Sbapt *val = true; 691247841Sbapt 692247841Sbapt return (0); 693247841Sbapt} 694247841Sbapt 695247841Sbaptvoid 696247841Sbaptconfig_finish(void) { 697247841Sbapt int i; 698247841Sbapt 699247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) 700247841Sbapt free(c[i].value); 701247841Sbapt} 702