config.c revision 261144
1247841Sbapt/*- 2247841Sbapt * Copyright (c) 2013 Baptiste Daroussin <bapt@FreeBSD.org> 3257353Sbdrewery * 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: stable/10/usr.sbin/pkg/config.c 261144 2014-01-25 01:08:35Z bapt $"); 30247841Sbapt 31247841Sbapt#include <sys/param.h> 32261144Sbapt#include <sys/queue.h> 33247841Sbapt#include <sys/sbuf.h> 34247841Sbapt#include <sys/elf_common.h> 35247841Sbapt#include <sys/endian.h> 36259613Sbdrewery#include <sys/types.h> 37247841Sbapt 38255457Sbapt#include <assert.h> 39259613Sbdrewery#include <dirent.h> 40256998Sbdrewery#include <yaml.h> 41247841Sbapt#include <ctype.h> 42247841Sbapt#include <err.h> 43247841Sbapt#include <errno.h> 44247841Sbapt#include <fcntl.h> 45247841Sbapt#include <gelf.h> 46247841Sbapt#include <inttypes.h> 47247841Sbapt#include <paths.h> 48247841Sbapt#include <stdbool.h> 49247841Sbapt#include <string.h> 50247841Sbapt#include <unistd.h> 51247841Sbapt 52247841Sbapt#include "elf_tables.h" 53247841Sbapt#include "config.h" 54247841Sbapt 55247841Sbapt#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */ 56247841Sbapt 57259613Sbdrewerystruct config_value { 58259613Sbdrewery char *value; 59259613Sbdrewery STAILQ_ENTRY(config_value) next; 60259613Sbdrewery}; 61259613Sbdrewery 62247841Sbaptstruct config_entry { 63247841Sbapt uint8_t type; 64247841Sbapt const char *key; 65247841Sbapt const char *val; 66247841Sbapt char *value; 67259613Sbdrewery STAILQ_HEAD(, config_value) *list; 68247841Sbapt bool envset; 69247841Sbapt}; 70247841Sbapt 71247841Sbaptstatic struct config_entry c[] = { 72247841Sbapt [PACKAGESITE] = { 73247841Sbapt PKG_CONFIG_STRING, 74247841Sbapt "PACKAGESITE", 75257328Sbdrewery URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 76247841Sbapt NULL, 77259613Sbdrewery NULL, 78247841Sbapt false, 79247841Sbapt }, 80247841Sbapt [ABI] = { 81247841Sbapt PKG_CONFIG_STRING, 82247841Sbapt "ABI", 83247841Sbapt NULL, 84247841Sbapt NULL, 85259613Sbdrewery NULL, 86247841Sbapt false, 87247841Sbapt }, 88247841Sbapt [MIRROR_TYPE] = { 89247841Sbapt PKG_CONFIG_STRING, 90247841Sbapt "MIRROR_TYPE", 91247841Sbapt "SRV", 92247841Sbapt NULL, 93259613Sbdrewery NULL, 94247841Sbapt false, 95247841Sbapt }, 96247841Sbapt [ASSUME_ALWAYS_YES] = { 97247841Sbapt PKG_CONFIG_BOOL, 98247841Sbapt "ASSUME_ALWAYS_YES", 99247841Sbapt "NO", 100247841Sbapt NULL, 101259613Sbdrewery NULL, 102247841Sbapt false, 103257353Sbdrewery }, 104257353Sbdrewery [SIGNATURE_TYPE] = { 105257353Sbdrewery PKG_CONFIG_STRING, 106257353Sbdrewery "SIGNATURE_TYPE", 107257353Sbdrewery NULL, 108257353Sbdrewery NULL, 109259613Sbdrewery NULL, 110257353Sbdrewery false, 111257353Sbdrewery }, 112257353Sbdrewery [FINGERPRINTS] = { 113257353Sbdrewery PKG_CONFIG_STRING, 114257353Sbdrewery "FINGERPRINTS", 115257353Sbdrewery NULL, 116257353Sbdrewery NULL, 117259613Sbdrewery NULL, 118257353Sbdrewery false, 119257353Sbdrewery }, 120259613Sbdrewery [REPOS_DIR] = { 121259613Sbdrewery PKG_CONFIG_LIST, 122259613Sbdrewery "REPOS_DIR", 123259613Sbdrewery NULL, 124259613Sbdrewery NULL, 125259613Sbdrewery NULL, 126259613Sbdrewery false, 127259613Sbdrewery }, 128247841Sbapt}; 129247841Sbapt 130247841Sbaptstatic const char * 131247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e) 132247841Sbapt{ 133247841Sbapt int i; 134247841Sbapt 135247841Sbapt for (i = 0; m[i].string != NULL; i++) 136247841Sbapt if (m[i].elf_nb == e) 137247841Sbapt return (m[i].string); 138247841Sbapt 139247841Sbapt return ("unknown"); 140247841Sbapt} 141247841Sbapt 142255457Sbaptstatic const char * 143255457Sbaptaeabi_parse_arm_attributes(void *data, size_t length) 144255457Sbapt{ 145255457Sbapt uint32_t sect_len; 146255457Sbapt uint8_t *section = data; 147255457Sbapt 148255457Sbapt#define MOVE(len) do { \ 149255457Sbapt assert(length >= (len)); \ 150255457Sbapt section += (len); \ 151255457Sbapt length -= (len); \ 152255457Sbapt} while (0) 153255457Sbapt 154255457Sbapt if (length == 0 || *section != 'A') 155255457Sbapt return (NULL); 156255457Sbapt 157255457Sbapt MOVE(1); 158255457Sbapt 159255457Sbapt /* Read the section length */ 160255457Sbapt if (length < sizeof(sect_len)) 161255457Sbapt return (NULL); 162255457Sbapt 163255457Sbapt memcpy(§_len, section, sizeof(sect_len)); 164255457Sbapt 165255457Sbapt /* 166255457Sbapt * The section length should be no longer than the section it is within 167255457Sbapt */ 168255457Sbapt if (sect_len > length) 169255457Sbapt return (NULL); 170255457Sbapt 171255457Sbapt MOVE(sizeof(sect_len)); 172255457Sbapt 173255457Sbapt /* Skip the vendor name */ 174255457Sbapt while (length != 0) { 175255457Sbapt if (*section == '\0') 176255457Sbapt break; 177255457Sbapt MOVE(1); 178255457Sbapt } 179255457Sbapt if (length == 0) 180255457Sbapt return (NULL); 181255457Sbapt MOVE(1); 182255457Sbapt 183255457Sbapt while (length != 0) { 184255457Sbapt uint32_t tag_length; 185255457Sbapt 186255457Sbapt switch(*section) { 187255457Sbapt case 1: /* Tag_File */ 188255457Sbapt MOVE(1); 189255457Sbapt if (length < sizeof(tag_length)) 190255457Sbapt return (NULL); 191255457Sbapt memcpy(&tag_length, section, sizeof(tag_length)); 192255457Sbapt break; 193255457Sbapt case 2: /* Tag_Section */ 194255457Sbapt case 3: /* Tag_Symbol */ 195255457Sbapt default: 196255457Sbapt return (NULL); 197255457Sbapt } 198255457Sbapt /* At least space for the tag and size */ 199255457Sbapt if (tag_length <= 5) 200255457Sbapt return (NULL); 201255457Sbapt tag_length--; 202255457Sbapt /* Check the tag fits */ 203255457Sbapt if (tag_length > length) 204255457Sbapt return (NULL); 205255457Sbapt 206255457Sbapt#define MOVE_TAG(len) do { \ 207255457Sbapt assert(tag_length >= (len)); \ 208255457Sbapt MOVE(len); \ 209255457Sbapt tag_length -= (len); \ 210255457Sbapt} while(0) 211255457Sbapt 212255457Sbapt MOVE(sizeof(tag_length)); 213255457Sbapt tag_length -= sizeof(tag_length); 214255457Sbapt 215255457Sbapt while (tag_length != 0) { 216255457Sbapt uint8_t tag; 217255457Sbapt 218255457Sbapt assert(tag_length >= length); 219255457Sbapt 220255457Sbapt tag = *section; 221255457Sbapt MOVE_TAG(1); 222255457Sbapt 223255457Sbapt /* 224255457Sbapt * These tag values come from: 225255457Sbapt * 226255457Sbapt * Addenda to, and Errata in, the ABI for the 227255457Sbapt * ARM Architecture. Release 2.08, section 2.3. 228255457Sbapt */ 229255457Sbapt if (tag == 6) { /* == Tag_CPU_arch */ 230255457Sbapt uint8_t val; 231255457Sbapt 232255457Sbapt val = *section; 233255457Sbapt /* 234255457Sbapt * We don't support values that require 235255457Sbapt * more than one byte. 236255457Sbapt */ 237255457Sbapt if (val & (1 << 7)) 238255457Sbapt return (NULL); 239255457Sbapt 240255457Sbapt /* We have an ARMv4 or ARMv5 */ 241255457Sbapt if (val <= 5) 242255457Sbapt return ("arm"); 243255457Sbapt else /* We have an ARMv6+ */ 244255457Sbapt return ("armv6"); 245255457Sbapt } else if (tag == 4 || tag == 5 || tag == 32 || 246255457Sbapt tag == 65 || tag == 67) { 247255457Sbapt while (*section != '\0' && length != 0) 248255457Sbapt MOVE_TAG(1); 249255457Sbapt if (tag_length == 0) 250255457Sbapt return (NULL); 251255457Sbapt /* Skip the last byte */ 252255457Sbapt MOVE_TAG(1); 253255457Sbapt } else if ((tag >= 7 && tag <= 31) || tag == 34 || 254255457Sbapt tag == 36 || tag == 38 || tag == 42 || tag == 44 || 255255457Sbapt tag == 64 || tag == 66 || tag == 68 || tag == 70) { 256255457Sbapt /* Skip the uleb128 data */ 257255457Sbapt while (*section & (1 << 7) && length != 0) 258255457Sbapt MOVE_TAG(1); 259255457Sbapt if (tag_length == 0) 260255457Sbapt return (NULL); 261255457Sbapt /* Skip the last byte */ 262255457Sbapt MOVE_TAG(1); 263255457Sbapt } else 264255457Sbapt return (NULL); 265255457Sbapt#undef MOVE_TAG 266255457Sbapt } 267255457Sbapt 268255457Sbapt break; 269255457Sbapt } 270255457Sbapt return (NULL); 271255457Sbapt#undef MOVE 272255457Sbapt} 273255457Sbapt 274247841Sbaptstatic int 275247841Sbaptpkg_get_myabi(char *dest, size_t sz) 276247841Sbapt{ 277247841Sbapt Elf *elf; 278247841Sbapt Elf_Data *data; 279247841Sbapt Elf_Note note; 280247841Sbapt Elf_Scn *scn; 281247841Sbapt char *src, *osname; 282255457Sbapt const char *arch, *abi, *fpu, *endian_corres_str; 283255457Sbapt const char *wordsize_corres_str; 284247841Sbapt GElf_Ehdr elfhdr; 285247841Sbapt GElf_Shdr shdr; 286247841Sbapt int fd, i, ret; 287247841Sbapt uint32_t version; 288247841Sbapt 289247841Sbapt version = 0; 290247841Sbapt ret = -1; 291247841Sbapt scn = NULL; 292247841Sbapt abi = NULL; 293247841Sbapt 294247841Sbapt if (elf_version(EV_CURRENT) == EV_NONE) { 295247841Sbapt warnx("ELF library initialization failed: %s", 296247841Sbapt elf_errmsg(-1)); 297247841Sbapt return (-1); 298247841Sbapt } 299247841Sbapt 300247841Sbapt if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 301247841Sbapt warn("open()"); 302247841Sbapt return (-1); 303247841Sbapt } 304247841Sbapt 305247841Sbapt if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 306247841Sbapt ret = -1; 307247841Sbapt warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 308247841Sbapt goto cleanup; 309247841Sbapt } 310247841Sbapt 311247841Sbapt if (gelf_getehdr(elf, &elfhdr) == NULL) { 312247841Sbapt ret = -1; 313247841Sbapt warn("getehdr() failed: %s.", elf_errmsg(-1)); 314247841Sbapt goto cleanup; 315247841Sbapt } 316247841Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 317247841Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 318247841Sbapt ret = -1; 319247841Sbapt warn("getshdr() failed: %s.", elf_errmsg(-1)); 320247841Sbapt goto cleanup; 321247841Sbapt } 322247841Sbapt 323247841Sbapt if (shdr.sh_type == SHT_NOTE) 324247841Sbapt break; 325247841Sbapt } 326247841Sbapt 327247841Sbapt if (scn == NULL) { 328247841Sbapt ret = -1; 329247841Sbapt warn("failed to get the note section"); 330247841Sbapt goto cleanup; 331247841Sbapt } 332247841Sbapt 333247841Sbapt data = elf_getdata(scn, NULL); 334247841Sbapt src = data->d_buf; 335247841Sbapt for (;;) { 336247841Sbapt memcpy(¬e, src, sizeof(Elf_Note)); 337247841Sbapt src += sizeof(Elf_Note); 338247841Sbapt if (note.n_type == NT_VERSION) 339247841Sbapt break; 340247841Sbapt src += note.n_namesz + note.n_descsz; 341247841Sbapt } 342247841Sbapt osname = src; 343247841Sbapt src += roundup2(note.n_namesz, 4); 344247841Sbapt if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 345247841Sbapt version = be32dec(src); 346247841Sbapt else 347247841Sbapt version = le32dec(src); 348247841Sbapt 349247841Sbapt for (i = 0; osname[i] != '\0'; i++) 350247841Sbapt osname[i] = (char)tolower(osname[i]); 351247841Sbapt 352255457Sbapt wordsize_corres_str = elf_corres_to_string(wordsize_corres, 353255457Sbapt (int)elfhdr.e_ident[EI_CLASS]); 354247841Sbapt 355255457Sbapt arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 356255457Sbapt 357255457Sbapt snprintf(dest, sz, "%s:%d", 358255457Sbapt osname, version / 100000); 359255457Sbapt 360247841Sbapt ret = 0; 361247841Sbapt 362247841Sbapt switch (elfhdr.e_machine) { 363247841Sbapt case EM_ARM: 364255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 365255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 366255457Sbapt 367253755Sbapt /* FreeBSD doesn't support the hard-float ABI yet */ 368253755Sbapt fpu = "softfp"; 369253755Sbapt if ((elfhdr.e_flags & 0xFF000000) != 0) { 370255457Sbapt const char *sh_name = NULL; 371255457Sbapt size_t shstrndx; 372255457Sbapt 373253755Sbapt /* This is an EABI file, the conformance level is set */ 374253755Sbapt abi = "eabi"; 375255457Sbapt /* Find which TARGET_ARCH we are building for. */ 376255457Sbapt elf_getshdrstrndx(elf, &shstrndx); 377255457Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 378255457Sbapt sh_name = NULL; 379255457Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 380255457Sbapt scn = NULL; 381255457Sbapt break; 382255457Sbapt } 383255457Sbapt 384255457Sbapt sh_name = elf_strptr(elf, shstrndx, 385255457Sbapt shdr.sh_name); 386255457Sbapt if (sh_name == NULL) 387255457Sbapt continue; 388255457Sbapt if (strcmp(".ARM.attributes", sh_name) == 0) 389255457Sbapt break; 390255457Sbapt } 391255457Sbapt if (scn != NULL && sh_name != NULL) { 392255457Sbapt data = elf_getdata(scn, NULL); 393255457Sbapt /* 394255457Sbapt * Prior to FreeBSD 10.0 libelf would return 395255457Sbapt * NULL from elf_getdata on the .ARM.attributes 396255457Sbapt * section. As this was the first release to 397255457Sbapt * get armv6 support assume a NULL value means 398255457Sbapt * arm. 399255457Sbapt * 400255457Sbapt * This assumption can be removed when 9.x 401255457Sbapt * is unsupported. 402255457Sbapt */ 403255457Sbapt if (data != NULL) { 404255457Sbapt arch = aeabi_parse_arm_attributes( 405255457Sbapt data->d_buf, data->d_size); 406255457Sbapt if (arch == NULL) { 407255457Sbapt ret = 1; 408255457Sbapt warn("unknown ARM ARCH"); 409255457Sbapt goto cleanup; 410255457Sbapt } 411255457Sbapt } 412255457Sbapt } else { 413255457Sbapt ret = 1; 414255457Sbapt warn("Unable to find the .ARM.attributes " 415255457Sbapt "section"); 416255457Sbapt goto cleanup; 417255457Sbapt } 418253755Sbapt } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 419253755Sbapt /* 420253755Sbapt * EABI executables all have this field set to 421253755Sbapt * ELFOSABI_NONE, therefore it must be an oabi file. 422253755Sbapt */ 423253755Sbapt abi = "oabi"; 424253755Sbapt } else { 425253755Sbapt ret = 1; 426255457Sbapt warn("unknown ARM ABI"); 427253755Sbapt goto cleanup; 428253755Sbapt } 429247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 430255457Sbapt ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 431255457Sbapt endian_corres_str, abi, fpu); 432247841Sbapt break; 433247841Sbapt case EM_MIPS: 434247841Sbapt /* 435247841Sbapt * this is taken from binutils sources: 436247841Sbapt * include/elf/mips.h 437247841Sbapt * mapping is figured out from binutils: 438247841Sbapt * gas/config/tc-mips.c 439247841Sbapt */ 440247841Sbapt switch (elfhdr.e_flags & EF_MIPS_ABI) { 441247841Sbapt case E_MIPS_ABI_O32: 442247841Sbapt abi = "o32"; 443247841Sbapt break; 444247841Sbapt case E_MIPS_ABI_N32: 445247841Sbapt abi = "n32"; 446247841Sbapt break; 447247841Sbapt default: 448247841Sbapt if (elfhdr.e_ident[EI_DATA] == 449247841Sbapt ELFCLASS32) 450247841Sbapt abi = "o32"; 451247841Sbapt else if (elfhdr.e_ident[EI_DATA] == 452247841Sbapt ELFCLASS64) 453247841Sbapt abi = "n64"; 454247841Sbapt break; 455247841Sbapt } 456255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 457255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 458255457Sbapt 459255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 460255457Sbapt arch, wordsize_corres_str, endian_corres_str, abi); 461247841Sbapt break; 462255457Sbapt default: 463255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 464255457Sbapt arch, wordsize_corres_str); 465247841Sbapt } 466247841Sbapt 467247841Sbaptcleanup: 468247841Sbapt if (elf != NULL) 469247841Sbapt elf_end(elf); 470247841Sbapt 471247841Sbapt close(fd); 472247841Sbapt return (ret); 473247841Sbapt} 474247841Sbapt 475247841Sbaptstatic void 476247841Sbaptsubst_packagesite(const char *abi) 477247841Sbapt{ 478247841Sbapt struct sbuf *newval; 479247841Sbapt const char *variable_string; 480247841Sbapt const char *oldval; 481247841Sbapt 482247841Sbapt if (c[PACKAGESITE].value != NULL) 483247841Sbapt oldval = c[PACKAGESITE].value; 484247841Sbapt else 485247841Sbapt oldval = c[PACKAGESITE].val; 486247841Sbapt 487247841Sbapt if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 488247841Sbapt return; 489247841Sbapt 490247841Sbapt newval = sbuf_new_auto(); 491247841Sbapt sbuf_bcat(newval, oldval, variable_string - oldval); 492247841Sbapt sbuf_cat(newval, abi); 493247841Sbapt sbuf_cat(newval, variable_string + strlen("${ABI}")); 494247841Sbapt sbuf_finish(newval); 495247841Sbapt 496247841Sbapt free(c[PACKAGESITE].value); 497247841Sbapt c[PACKAGESITE].value = strdup(sbuf_data(newval)); 498247841Sbapt} 499247841Sbapt 500259613Sbdrewerystatic int 501259613Sbdreweryboolstr_to_bool(const char *str) 502259613Sbdrewery{ 503259613Sbdrewery if (str != NULL && (strcasecmp(str, "true") == 0 || 504259613Sbdrewery strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 505259613Sbdrewery str[0] == '1')) 506259613Sbdrewery return (true); 507259613Sbdrewery 508259613Sbdrewery return (false); 509259613Sbdrewery} 510259613Sbdrewery 511247841Sbaptstatic void 512257353Sbdreweryconfig_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype) 513247841Sbapt{ 514259613Sbdrewery yaml_node_item_t *item; 515247841Sbapt yaml_node_pair_t *pair; 516259613Sbdrewery yaml_node_t *key, *val, *item_val; 517247841Sbapt struct sbuf *buf = sbuf_new_auto(); 518259613Sbdrewery struct config_entry *temp_config; 519259613Sbdrewery struct config_value *cv; 520247841Sbapt int i; 521247841Sbapt size_t j; 522247841Sbapt 523247841Sbapt pair = node->data.mapping.pairs.start; 524247841Sbapt 525259613Sbdrewery /* Temporary config for configs that may be disabled. */ 526259613Sbdrewery temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 527259613Sbdrewery 528247841Sbapt while (pair < node->data.mapping.pairs.top) { 529247841Sbapt key = yaml_document_get_node(doc, pair->key); 530247841Sbapt val = yaml_document_get_node(doc, pair->value); 531247841Sbapt 532247841Sbapt /* 533247841Sbapt * ignoring silently empty keys can be empty lines 534247841Sbapt * or user mistakes 535247841Sbapt */ 536247841Sbapt if (key->data.scalar.length <= 0) { 537247841Sbapt ++pair; 538247841Sbapt continue; 539247841Sbapt } 540247841Sbapt 541247841Sbapt /* 542247841Sbapt * silently skip on purpose to allow user to leave 543247841Sbapt * empty lines without complaining 544247841Sbapt */ 545247841Sbapt if (val->type == YAML_NO_NODE || 546247841Sbapt (val->type == YAML_SCALAR_NODE && 547247841Sbapt val->data.scalar.length <= 0)) { 548247841Sbapt ++pair; 549247841Sbapt continue; 550247841Sbapt } 551247841Sbapt 552247841Sbapt sbuf_clear(buf); 553247841Sbapt 554257353Sbdrewery if (conftype == CONFFILE_PKG) { 555257353Sbdrewery for (j = 0; j < strlen(key->data.scalar.value); ++j) 556257353Sbdrewery sbuf_putc(buf, 557257353Sbdrewery toupper(key->data.scalar.value[j])); 558257353Sbdrewery sbuf_finish(buf); 559257353Sbdrewery } else if (conftype == CONFFILE_REPO) { 560257353Sbdrewery /* The CONFFILE_REPO type is more restrictive. Only 561257353Sbdrewery parse known elements. */ 562257353Sbdrewery if (strcasecmp(key->data.scalar.value, "url") == 0) 563257353Sbdrewery sbuf_cpy(buf, "PACKAGESITE"); 564257353Sbdrewery else if (strcasecmp(key->data.scalar.value, 565257353Sbdrewery "mirror_type") == 0) 566257353Sbdrewery sbuf_cpy(buf, "MIRROR_TYPE"); 567257353Sbdrewery else if (strcasecmp(key->data.scalar.value, 568257353Sbdrewery "signature_type") == 0) 569257353Sbdrewery sbuf_cpy(buf, "SIGNATURE_TYPE"); 570257353Sbdrewery else if (strcasecmp(key->data.scalar.value, 571257353Sbdrewery "fingerprints") == 0) 572257353Sbdrewery sbuf_cpy(buf, "FINGERPRINTS"); 573259613Sbdrewery else if (strcasecmp(key->data.scalar.value, 574259613Sbdrewery "enabled") == 0) { 575259613Sbdrewery /* Skip disabled repos. */ 576259613Sbdrewery if (!boolstr_to_bool(val->data.scalar.value)) 577259613Sbdrewery goto cleanup; 578259613Sbdrewery } else { /* Skip unknown entries for future use. */ 579257353Sbdrewery ++pair; 580257353Sbdrewery continue; 581257353Sbdrewery } 582257353Sbdrewery sbuf_finish(buf); 583257353Sbdrewery } 584257353Sbdrewery 585247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 586247841Sbapt if (strcmp(sbuf_data(buf), c[i].key) == 0) 587247841Sbapt break; 588247841Sbapt } 589247841Sbapt 590257353Sbdrewery /* Silently skip unknown keys to be future compatible. */ 591247841Sbapt if (i == CONFIG_SIZE) { 592247841Sbapt ++pair; 593247841Sbapt continue; 594247841Sbapt } 595247841Sbapt 596247841Sbapt /* env has priority over config file */ 597247841Sbapt if (c[i].envset) { 598247841Sbapt ++pair; 599247841Sbapt continue; 600247841Sbapt } 601247841Sbapt 602259613Sbdrewery /* Parse sequence value ["item1", "item2"] */ 603259613Sbdrewery switch (c[i].type) { 604259613Sbdrewery case PKG_CONFIG_LIST: 605259613Sbdrewery if (val->type != YAML_SEQUENCE_NODE) { 606259613Sbdrewery fprintf(stderr, "Skipping invalid array " 607259613Sbdrewery "value for %s.\n", c[i].key); 608259613Sbdrewery ++pair; 609259613Sbdrewery continue; 610259613Sbdrewery } 611259613Sbdrewery item = val->data.sequence.items.start; 612259613Sbdrewery temp_config[i].list = 613259613Sbdrewery malloc(sizeof(*temp_config[i].list)); 614259613Sbdrewery STAILQ_INIT(temp_config[i].list); 615259613Sbdrewery 616259613Sbdrewery while (item < val->data.sequence.items.top) { 617259613Sbdrewery item_val = yaml_document_get_node(doc, *item); 618259613Sbdrewery if (item_val->type != YAML_SCALAR_NODE) { 619259613Sbdrewery ++item; 620259613Sbdrewery continue; 621259613Sbdrewery } 622259613Sbdrewery cv = malloc(sizeof(struct config_value)); 623259613Sbdrewery cv->value = 624259613Sbdrewery strdup(item_val->data.scalar.value); 625259613Sbdrewery STAILQ_INSERT_TAIL(temp_config[i].list, cv, 626259613Sbdrewery next); 627259613Sbdrewery ++item; 628259613Sbdrewery } 629259613Sbdrewery break; 630259613Sbdrewery default: 631259613Sbdrewery /* Normal string value. */ 632259613Sbdrewery temp_config[i].value = strdup(val->data.scalar.value); 633259613Sbdrewery break; 634259613Sbdrewery } 635247841Sbapt ++pair; 636247841Sbapt } 637247841Sbapt 638259613Sbdrewery /* Repo is enabled, copy over all settings from temp_config. */ 639259613Sbdrewery for (i = 0; i < CONFIG_SIZE; i++) { 640259613Sbdrewery if (c[i].envset) 641259613Sbdrewery continue; 642259613Sbdrewery switch (c[i].type) { 643259613Sbdrewery case PKG_CONFIG_LIST: 644259613Sbdrewery c[i].list = temp_config[i].list; 645259613Sbdrewery break; 646259613Sbdrewery default: 647259613Sbdrewery c[i].value = temp_config[i].value; 648259613Sbdrewery break; 649259613Sbdrewery } 650259613Sbdrewery } 651259613Sbdrewery 652259613Sbdrewerycleanup: 653259613Sbdrewery free(temp_config); 654247841Sbapt sbuf_delete(buf); 655247841Sbapt} 656247841Sbapt 657257353Sbdrewery/*- 658257353Sbdrewery * Parse new repo style configs in style: 659257353Sbdrewery * Name: 660257353Sbdrewery * URL: 661257353Sbdrewery * MIRROR_TYPE: 662257353Sbdrewery * etc... 663257353Sbdrewery */ 664257353Sbdrewerystatic void 665257353Sbdreweryparse_repo_file(yaml_document_t *doc, yaml_node_t *node) 666247841Sbapt{ 667257353Sbdrewery yaml_node_pair_t *pair; 668257353Sbdrewery 669257353Sbdrewery pair = node->data.mapping.pairs.start; 670257353Sbdrewery while (pair < node->data.mapping.pairs.top) { 671257353Sbdrewery yaml_node_t *key = yaml_document_get_node(doc, pair->key); 672257353Sbdrewery yaml_node_t *val = yaml_document_get_node(doc, pair->value); 673257353Sbdrewery 674257353Sbdrewery if (key->data.scalar.length <= 0) { 675257353Sbdrewery ++pair; 676257353Sbdrewery continue; 677257353Sbdrewery } 678257353Sbdrewery 679257353Sbdrewery if (val->type != YAML_MAPPING_NODE) { 680257353Sbdrewery ++pair; 681257353Sbdrewery continue; 682257353Sbdrewery } 683257353Sbdrewery 684257353Sbdrewery config_parse(doc, val, CONFFILE_REPO); 685257353Sbdrewery ++pair; 686257353Sbdrewery } 687257353Sbdrewery} 688257353Sbdrewery 689257353Sbdrewery 690257353Sbdrewerystatic int 691257353Sbdreweryread_conf_file(const char *confpath, pkg_conf_file_t conftype) 692257353Sbdrewery{ 693247841Sbapt FILE *fp; 694247841Sbapt yaml_parser_t parser; 695247841Sbapt yaml_document_t doc; 696247841Sbapt yaml_node_t *node; 697257353Sbdrewery 698257353Sbdrewery if ((fp = fopen(confpath, "r")) == NULL) { 699257353Sbdrewery if (errno != ENOENT) 700257353Sbdrewery err(EXIT_FAILURE, "Unable to open configuration " 701257353Sbdrewery "file %s", confpath); 702257353Sbdrewery /* no configuration present */ 703257353Sbdrewery return (1); 704257353Sbdrewery } 705257353Sbdrewery 706257353Sbdrewery yaml_parser_initialize(&parser); 707257353Sbdrewery yaml_parser_set_input_file(&parser, fp); 708257353Sbdrewery yaml_parser_load(&parser, &doc); 709257353Sbdrewery 710257353Sbdrewery node = yaml_document_get_root_node(&doc); 711257353Sbdrewery 712257353Sbdrewery if (node == NULL || node->type != YAML_MAPPING_NODE) 713257353Sbdrewery warnx("Invalid configuration format, ignoring the " 714257353Sbdrewery "configuration file %s", confpath); 715257353Sbdrewery else { 716257353Sbdrewery if (conftype == CONFFILE_PKG) 717257353Sbdrewery config_parse(&doc, node, conftype); 718257353Sbdrewery else if (conftype == CONFFILE_REPO) 719257353Sbdrewery parse_repo_file(&doc, node); 720257353Sbdrewery } 721257353Sbdrewery 722257353Sbdrewery yaml_document_delete(&doc); 723257353Sbdrewery yaml_parser_delete(&parser); 724257353Sbdrewery 725257353Sbdrewery return (0); 726257353Sbdrewery} 727257353Sbdrewery 728259613Sbdrewerystatic int 729259613Sbdreweryload_repositories(const char *repodir) 730259613Sbdrewery{ 731259613Sbdrewery struct dirent *ent; 732259613Sbdrewery DIR *d; 733259613Sbdrewery char *p; 734259613Sbdrewery size_t n; 735259613Sbdrewery char path[MAXPATHLEN]; 736259613Sbdrewery int ret; 737259613Sbdrewery 738259613Sbdrewery ret = 0; 739259613Sbdrewery 740259613Sbdrewery if ((d = opendir(repodir)) == NULL) 741259613Sbdrewery return (1); 742259613Sbdrewery 743259613Sbdrewery while ((ent = readdir(d))) { 744259613Sbdrewery /* Trim out 'repos'. */ 745259613Sbdrewery if ((n = strlen(ent->d_name)) <= 5) 746259613Sbdrewery continue; 747259613Sbdrewery p = &ent->d_name[n - 5]; 748259613Sbdrewery if (strcmp(p, ".conf") == 0) { 749259613Sbdrewery snprintf(path, sizeof(path), "%s%s%s", 750259613Sbdrewery repodir, 751259613Sbdrewery repodir[strlen(repodir) - 1] == '/' ? "" : "/", 752259613Sbdrewery ent->d_name); 753259613Sbdrewery if (access(path, F_OK) == 0 && 754259613Sbdrewery read_conf_file(path, CONFFILE_REPO)) { 755259613Sbdrewery ret = 1; 756259613Sbdrewery goto cleanup; 757259613Sbdrewery } 758259613Sbdrewery } 759259613Sbdrewery } 760259613Sbdrewery 761259613Sbdrewerycleanup: 762259613Sbdrewery closedir(d); 763259613Sbdrewery 764259613Sbdrewery return (ret); 765259613Sbdrewery} 766259613Sbdrewery 767257353Sbdreweryint 768257353Sbdreweryconfig_init(void) 769257353Sbdrewery{ 770259613Sbdrewery char *val; 771247841Sbapt int i; 772247841Sbapt const char *localbase; 773259613Sbdrewery char *env_list_item; 774247841Sbapt char confpath[MAXPATHLEN]; 775259613Sbdrewery struct config_value *cv; 776247841Sbapt char abi[BUFSIZ]; 777247841Sbapt 778247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 779247841Sbapt val = getenv(c[i].key); 780247841Sbapt if (val != NULL) { 781247841Sbapt c[i].envset = true; 782259613Sbdrewery switch (c[i].type) { 783259613Sbdrewery case PKG_CONFIG_LIST: 784259613Sbdrewery /* Split up comma-separated items from env. */ 785259613Sbdrewery c[i].list = malloc(sizeof(*c[i].list)); 786259613Sbdrewery STAILQ_INIT(c[i].list); 787259613Sbdrewery for (env_list_item = strtok(val, ","); 788259613Sbdrewery env_list_item != NULL; 789259613Sbdrewery env_list_item = strtok(NULL, ",")) { 790259613Sbdrewery cv = 791259613Sbdrewery malloc(sizeof(struct config_value)); 792259613Sbdrewery cv->value = 793259613Sbdrewery strdup(env_list_item); 794259613Sbdrewery STAILQ_INSERT_TAIL(c[i].list, cv, 795259613Sbdrewery next); 796259613Sbdrewery } 797259613Sbdrewery break; 798259613Sbdrewery default: 799259613Sbdrewery c[i].val = val; 800259613Sbdrewery break; 801259613Sbdrewery } 802247841Sbapt } 803247841Sbapt } 804247841Sbapt 805259613Sbdrewery /* Read LOCALBASE/etc/pkg.conf first. */ 806247841Sbapt localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 807257353Sbdrewery snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 808257353Sbdrewery localbase); 809247841Sbapt 810257353Sbdrewery if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 811257353Sbdrewery CONFFILE_PKG)) 812247841Sbapt goto finalize; 813247841Sbapt 814259613Sbdrewery /* Then read in all repos from REPOS_DIR list of directories. */ 815259613Sbdrewery if (c[REPOS_DIR].list == NULL) { 816259613Sbdrewery c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 817259613Sbdrewery STAILQ_INIT(c[REPOS_DIR].list); 818259613Sbdrewery cv = malloc(sizeof(struct config_value)); 819259613Sbdrewery cv->value = strdup("/etc/pkg"); 820259613Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 821259613Sbdrewery cv = malloc(sizeof(struct config_value)); 822259613Sbdrewery if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 823259613Sbdrewery goto finalize; 824259613Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 825259613Sbdrewery } 826247841Sbapt 827259613Sbdrewery STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 828259613Sbdrewery if (load_repositories(cv->value)) 829259613Sbdrewery goto finalize; 830259613Sbdrewery 831247841Sbaptfinalize: 832247841Sbapt if (c[ABI].val == NULL && c[ABI].value == NULL) { 833247841Sbapt if (pkg_get_myabi(abi, BUFSIZ) != 0) 834257353Sbdrewery errx(EXIT_FAILURE, "Failed to determine the system " 835257353Sbdrewery "ABI"); 836247841Sbapt c[ABI].val = abi; 837247841Sbapt } 838247841Sbapt 839247843Sbapt subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 840247841Sbapt 841247841Sbapt return (0); 842247841Sbapt} 843247841Sbapt 844247841Sbaptint 845247841Sbaptconfig_string(pkg_config_key k, const char **val) 846247841Sbapt{ 847247841Sbapt if (c[k].type != PKG_CONFIG_STRING) 848247841Sbapt return (-1); 849247841Sbapt 850247841Sbapt if (c[k].value != NULL) 851247841Sbapt *val = c[k].value; 852247841Sbapt else 853247841Sbapt *val = c[k].val; 854247841Sbapt 855247841Sbapt return (0); 856247841Sbapt} 857247841Sbapt 858247841Sbaptint 859247841Sbaptconfig_bool(pkg_config_key k, bool *val) 860247841Sbapt{ 861247841Sbapt const char *value; 862247841Sbapt 863247841Sbapt if (c[k].type != PKG_CONFIG_BOOL) 864247841Sbapt return (-1); 865247841Sbapt 866247841Sbapt *val = false; 867247841Sbapt 868247841Sbapt if (c[k].value != NULL) 869247841Sbapt value = c[k].value; 870247841Sbapt else 871247841Sbapt value = c[k].val; 872247841Sbapt 873259613Sbdrewery if (boolstr_to_bool(value)) 874247841Sbapt *val = true; 875247841Sbapt 876247841Sbapt return (0); 877247841Sbapt} 878247841Sbapt 879247841Sbaptvoid 880247841Sbaptconfig_finish(void) { 881247841Sbapt int i; 882247841Sbapt 883247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) 884247841Sbapt free(c[i].value); 885247841Sbapt} 886