config.c revision 263181
1247841Sbapt/*- 2262401Sbapt * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org> 3257147Sbdrewery * 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: head/usr.sbin/pkg/config.c 263181 2014-03-14 17:37:38Z bdrewery $"); 30247841Sbapt 31247841Sbapt#include <sys/param.h> 32260942Sbapt#include <sys/queue.h> 33247841Sbapt#include <sys/sbuf.h> 34247841Sbapt#include <sys/elf_common.h> 35247841Sbapt#include <sys/endian.h> 36259266Sbdrewery#include <sys/types.h> 37247841Sbapt 38255457Sbapt#include <assert.h> 39259266Sbdrewery#include <dirent.h> 40262400Sbapt#include <ucl.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 57259266Sbdrewerystruct config_value { 58259266Sbdrewery char *value; 59259266Sbdrewery STAILQ_ENTRY(config_value) next; 60259266Sbdrewery}; 61259266Sbdrewery 62247841Sbaptstruct config_entry { 63247841Sbapt uint8_t type; 64247841Sbapt const char *key; 65247841Sbapt const char *val; 66247841Sbapt char *value; 67259266Sbdrewery STAILQ_HEAD(, config_value) *list; 68247841Sbapt bool envset; 69263180Sbdrewery bool main_only; /* Only set in pkg.conf. */ 70247841Sbapt}; 71247841Sbapt 72247841Sbaptstatic struct config_entry c[] = { 73247841Sbapt [PACKAGESITE] = { 74247841Sbapt PKG_CONFIG_STRING, 75247841Sbapt "PACKAGESITE", 76257051Sbdrewery URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 77247841Sbapt NULL, 78259266Sbdrewery NULL, 79247841Sbapt false, 80263180Sbdrewery false, 81247841Sbapt }, 82247841Sbapt [ABI] = { 83247841Sbapt PKG_CONFIG_STRING, 84247841Sbapt "ABI", 85247841Sbapt NULL, 86247841Sbapt NULL, 87259266Sbdrewery NULL, 88247841Sbapt false, 89263180Sbdrewery true, 90247841Sbapt }, 91247841Sbapt [MIRROR_TYPE] = { 92247841Sbapt PKG_CONFIG_STRING, 93247841Sbapt "MIRROR_TYPE", 94247841Sbapt "SRV", 95247841Sbapt NULL, 96259266Sbdrewery NULL, 97247841Sbapt false, 98263180Sbdrewery false, 99247841Sbapt }, 100247841Sbapt [ASSUME_ALWAYS_YES] = { 101247841Sbapt PKG_CONFIG_BOOL, 102247841Sbapt "ASSUME_ALWAYS_YES", 103247841Sbapt "NO", 104247841Sbapt NULL, 105259266Sbdrewery NULL, 106247841Sbapt false, 107263180Sbdrewery true, 108257147Sbdrewery }, 109257147Sbdrewery [SIGNATURE_TYPE] = { 110257147Sbdrewery PKG_CONFIG_STRING, 111257147Sbdrewery "SIGNATURE_TYPE", 112257147Sbdrewery NULL, 113257147Sbdrewery NULL, 114259266Sbdrewery NULL, 115257147Sbdrewery false, 116263180Sbdrewery false, 117257147Sbdrewery }, 118257147Sbdrewery [FINGERPRINTS] = { 119257147Sbdrewery PKG_CONFIG_STRING, 120257147Sbdrewery "FINGERPRINTS", 121257147Sbdrewery NULL, 122257147Sbdrewery NULL, 123259266Sbdrewery NULL, 124257147Sbdrewery false, 125263180Sbdrewery false, 126257147Sbdrewery }, 127259266Sbdrewery [REPOS_DIR] = { 128259266Sbdrewery PKG_CONFIG_LIST, 129259266Sbdrewery "REPOS_DIR", 130259266Sbdrewery NULL, 131259266Sbdrewery NULL, 132259266Sbdrewery NULL, 133259266Sbdrewery false, 134263180Sbdrewery true, 135259266Sbdrewery }, 136247841Sbapt}; 137247841Sbapt 138247841Sbaptstatic const char * 139247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e) 140247841Sbapt{ 141247841Sbapt int i; 142247841Sbapt 143247841Sbapt for (i = 0; m[i].string != NULL; i++) 144247841Sbapt if (m[i].elf_nb == e) 145247841Sbapt return (m[i].string); 146247841Sbapt 147247841Sbapt return ("unknown"); 148247841Sbapt} 149247841Sbapt 150255457Sbaptstatic const char * 151255457Sbaptaeabi_parse_arm_attributes(void *data, size_t length) 152255457Sbapt{ 153255457Sbapt uint32_t sect_len; 154255457Sbapt uint8_t *section = data; 155255457Sbapt 156255457Sbapt#define MOVE(len) do { \ 157255457Sbapt assert(length >= (len)); \ 158255457Sbapt section += (len); \ 159255457Sbapt length -= (len); \ 160255457Sbapt} while (0) 161255457Sbapt 162255457Sbapt if (length == 0 || *section != 'A') 163255457Sbapt return (NULL); 164255457Sbapt 165255457Sbapt MOVE(1); 166255457Sbapt 167255457Sbapt /* Read the section length */ 168255457Sbapt if (length < sizeof(sect_len)) 169255457Sbapt return (NULL); 170255457Sbapt 171255457Sbapt memcpy(§_len, section, sizeof(sect_len)); 172255457Sbapt 173255457Sbapt /* 174255457Sbapt * The section length should be no longer than the section it is within 175255457Sbapt */ 176255457Sbapt if (sect_len > length) 177255457Sbapt return (NULL); 178255457Sbapt 179255457Sbapt MOVE(sizeof(sect_len)); 180255457Sbapt 181255457Sbapt /* Skip the vendor name */ 182255457Sbapt while (length != 0) { 183255457Sbapt if (*section == '\0') 184255457Sbapt break; 185255457Sbapt MOVE(1); 186255457Sbapt } 187255457Sbapt if (length == 0) 188255457Sbapt return (NULL); 189255457Sbapt MOVE(1); 190255457Sbapt 191255457Sbapt while (length != 0) { 192255457Sbapt uint32_t tag_length; 193255457Sbapt 194255457Sbapt switch(*section) { 195255457Sbapt case 1: /* Tag_File */ 196255457Sbapt MOVE(1); 197255457Sbapt if (length < sizeof(tag_length)) 198255457Sbapt return (NULL); 199255457Sbapt memcpy(&tag_length, section, sizeof(tag_length)); 200255457Sbapt break; 201255457Sbapt case 2: /* Tag_Section */ 202255457Sbapt case 3: /* Tag_Symbol */ 203255457Sbapt default: 204255457Sbapt return (NULL); 205255457Sbapt } 206255457Sbapt /* At least space for the tag and size */ 207255457Sbapt if (tag_length <= 5) 208255457Sbapt return (NULL); 209255457Sbapt tag_length--; 210255457Sbapt /* Check the tag fits */ 211255457Sbapt if (tag_length > length) 212255457Sbapt return (NULL); 213255457Sbapt 214255457Sbapt#define MOVE_TAG(len) do { \ 215255457Sbapt assert(tag_length >= (len)); \ 216255457Sbapt MOVE(len); \ 217255457Sbapt tag_length -= (len); \ 218255457Sbapt} while(0) 219255457Sbapt 220255457Sbapt MOVE(sizeof(tag_length)); 221255457Sbapt tag_length -= sizeof(tag_length); 222255457Sbapt 223255457Sbapt while (tag_length != 0) { 224255457Sbapt uint8_t tag; 225255457Sbapt 226255457Sbapt assert(tag_length >= length); 227255457Sbapt 228255457Sbapt tag = *section; 229255457Sbapt MOVE_TAG(1); 230255457Sbapt 231255457Sbapt /* 232255457Sbapt * These tag values come from: 233255457Sbapt * 234255457Sbapt * Addenda to, and Errata in, the ABI for the 235255457Sbapt * ARM Architecture. Release 2.08, section 2.3. 236255457Sbapt */ 237255457Sbapt if (tag == 6) { /* == Tag_CPU_arch */ 238255457Sbapt uint8_t val; 239255457Sbapt 240255457Sbapt val = *section; 241255457Sbapt /* 242255457Sbapt * We don't support values that require 243255457Sbapt * more than one byte. 244255457Sbapt */ 245255457Sbapt if (val & (1 << 7)) 246255457Sbapt return (NULL); 247255457Sbapt 248255457Sbapt /* We have an ARMv4 or ARMv5 */ 249255457Sbapt if (val <= 5) 250255457Sbapt return ("arm"); 251255457Sbapt else /* We have an ARMv6+ */ 252255457Sbapt return ("armv6"); 253255457Sbapt } else if (tag == 4 || tag == 5 || tag == 32 || 254255457Sbapt tag == 65 || tag == 67) { 255255457Sbapt while (*section != '\0' && length != 0) 256255457Sbapt MOVE_TAG(1); 257255457Sbapt if (tag_length == 0) 258255457Sbapt return (NULL); 259255457Sbapt /* Skip the last byte */ 260255457Sbapt MOVE_TAG(1); 261255457Sbapt } else if ((tag >= 7 && tag <= 31) || tag == 34 || 262255457Sbapt tag == 36 || tag == 38 || tag == 42 || tag == 44 || 263255457Sbapt tag == 64 || tag == 66 || tag == 68 || tag == 70) { 264255457Sbapt /* Skip the uleb128 data */ 265255457Sbapt while (*section & (1 << 7) && length != 0) 266255457Sbapt MOVE_TAG(1); 267255457Sbapt if (tag_length == 0) 268255457Sbapt return (NULL); 269255457Sbapt /* Skip the last byte */ 270255457Sbapt MOVE_TAG(1); 271255457Sbapt } else 272255457Sbapt return (NULL); 273255457Sbapt#undef MOVE_TAG 274255457Sbapt } 275255457Sbapt 276255457Sbapt break; 277255457Sbapt } 278255457Sbapt return (NULL); 279255457Sbapt#undef MOVE 280255457Sbapt} 281255457Sbapt 282247841Sbaptstatic int 283247841Sbaptpkg_get_myabi(char *dest, size_t sz) 284247841Sbapt{ 285247841Sbapt Elf *elf; 286247841Sbapt Elf_Data *data; 287247841Sbapt Elf_Note note; 288247841Sbapt Elf_Scn *scn; 289247841Sbapt char *src, *osname; 290255457Sbapt const char *arch, *abi, *fpu, *endian_corres_str; 291255457Sbapt const char *wordsize_corres_str; 292247841Sbapt GElf_Ehdr elfhdr; 293247841Sbapt GElf_Shdr shdr; 294247841Sbapt int fd, i, ret; 295247841Sbapt uint32_t version; 296247841Sbapt 297247841Sbapt version = 0; 298247841Sbapt ret = -1; 299247841Sbapt scn = NULL; 300247841Sbapt abi = NULL; 301247841Sbapt 302247841Sbapt if (elf_version(EV_CURRENT) == EV_NONE) { 303247841Sbapt warnx("ELF library initialization failed: %s", 304247841Sbapt elf_errmsg(-1)); 305247841Sbapt return (-1); 306247841Sbapt } 307247841Sbapt 308247841Sbapt if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 309247841Sbapt warn("open()"); 310247841Sbapt return (-1); 311247841Sbapt } 312247841Sbapt 313247841Sbapt if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 314247841Sbapt ret = -1; 315247841Sbapt warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 316247841Sbapt goto cleanup; 317247841Sbapt } 318247841Sbapt 319247841Sbapt if (gelf_getehdr(elf, &elfhdr) == NULL) { 320247841Sbapt ret = -1; 321247841Sbapt warn("getehdr() failed: %s.", elf_errmsg(-1)); 322247841Sbapt goto cleanup; 323247841Sbapt } 324247841Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 325247841Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 326247841Sbapt ret = -1; 327247841Sbapt warn("getshdr() failed: %s.", elf_errmsg(-1)); 328247841Sbapt goto cleanup; 329247841Sbapt } 330247841Sbapt 331247841Sbapt if (shdr.sh_type == SHT_NOTE) 332247841Sbapt break; 333247841Sbapt } 334247841Sbapt 335247841Sbapt if (scn == NULL) { 336247841Sbapt ret = -1; 337247841Sbapt warn("failed to get the note section"); 338247841Sbapt goto cleanup; 339247841Sbapt } 340247841Sbapt 341247841Sbapt data = elf_getdata(scn, NULL); 342247841Sbapt src = data->d_buf; 343247841Sbapt for (;;) { 344247841Sbapt memcpy(¬e, src, sizeof(Elf_Note)); 345247841Sbapt src += sizeof(Elf_Note); 346247841Sbapt if (note.n_type == NT_VERSION) 347247841Sbapt break; 348247841Sbapt src += note.n_namesz + note.n_descsz; 349247841Sbapt } 350247841Sbapt osname = src; 351247841Sbapt src += roundup2(note.n_namesz, 4); 352247841Sbapt if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 353247841Sbapt version = be32dec(src); 354247841Sbapt else 355247841Sbapt version = le32dec(src); 356247841Sbapt 357247841Sbapt for (i = 0; osname[i] != '\0'; i++) 358247841Sbapt osname[i] = (char)tolower(osname[i]); 359247841Sbapt 360255457Sbapt wordsize_corres_str = elf_corres_to_string(wordsize_corres, 361255457Sbapt (int)elfhdr.e_ident[EI_CLASS]); 362247841Sbapt 363255457Sbapt arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 364255457Sbapt 365255457Sbapt snprintf(dest, sz, "%s:%d", 366255457Sbapt osname, version / 100000); 367255457Sbapt 368247841Sbapt ret = 0; 369247841Sbapt 370247841Sbapt switch (elfhdr.e_machine) { 371247841Sbapt case EM_ARM: 372255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 373255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 374255457Sbapt 375253755Sbapt /* FreeBSD doesn't support the hard-float ABI yet */ 376253755Sbapt fpu = "softfp"; 377253755Sbapt if ((elfhdr.e_flags & 0xFF000000) != 0) { 378255457Sbapt const char *sh_name = NULL; 379255457Sbapt size_t shstrndx; 380255457Sbapt 381253755Sbapt /* This is an EABI file, the conformance level is set */ 382253755Sbapt abi = "eabi"; 383255457Sbapt /* Find which TARGET_ARCH we are building for. */ 384255457Sbapt elf_getshdrstrndx(elf, &shstrndx); 385255457Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 386255457Sbapt sh_name = NULL; 387255457Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 388255457Sbapt scn = NULL; 389255457Sbapt break; 390255457Sbapt } 391255457Sbapt 392255457Sbapt sh_name = elf_strptr(elf, shstrndx, 393255457Sbapt shdr.sh_name); 394255457Sbapt if (sh_name == NULL) 395255457Sbapt continue; 396255457Sbapt if (strcmp(".ARM.attributes", sh_name) == 0) 397255457Sbapt break; 398255457Sbapt } 399255457Sbapt if (scn != NULL && sh_name != NULL) { 400255457Sbapt data = elf_getdata(scn, NULL); 401255457Sbapt /* 402255457Sbapt * Prior to FreeBSD 10.0 libelf would return 403255457Sbapt * NULL from elf_getdata on the .ARM.attributes 404255457Sbapt * section. As this was the first release to 405255457Sbapt * get armv6 support assume a NULL value means 406255457Sbapt * arm. 407255457Sbapt * 408255457Sbapt * This assumption can be removed when 9.x 409255457Sbapt * is unsupported. 410255457Sbapt */ 411255457Sbapt if (data != NULL) { 412255457Sbapt arch = aeabi_parse_arm_attributes( 413255457Sbapt data->d_buf, data->d_size); 414255457Sbapt if (arch == NULL) { 415255457Sbapt ret = 1; 416255457Sbapt warn("unknown ARM ARCH"); 417255457Sbapt goto cleanup; 418255457Sbapt } 419255457Sbapt } 420255457Sbapt } else { 421255457Sbapt ret = 1; 422255457Sbapt warn("Unable to find the .ARM.attributes " 423255457Sbapt "section"); 424255457Sbapt goto cleanup; 425255457Sbapt } 426253755Sbapt } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 427253755Sbapt /* 428253755Sbapt * EABI executables all have this field set to 429253755Sbapt * ELFOSABI_NONE, therefore it must be an oabi file. 430253755Sbapt */ 431253755Sbapt abi = "oabi"; 432253755Sbapt } else { 433253755Sbapt ret = 1; 434255457Sbapt warn("unknown ARM ABI"); 435253755Sbapt goto cleanup; 436253755Sbapt } 437247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 438255457Sbapt ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 439255457Sbapt endian_corres_str, abi, fpu); 440247841Sbapt break; 441247841Sbapt case EM_MIPS: 442247841Sbapt /* 443247841Sbapt * this is taken from binutils sources: 444247841Sbapt * include/elf/mips.h 445247841Sbapt * mapping is figured out from binutils: 446247841Sbapt * gas/config/tc-mips.c 447247841Sbapt */ 448247841Sbapt switch (elfhdr.e_flags & EF_MIPS_ABI) { 449247841Sbapt case E_MIPS_ABI_O32: 450247841Sbapt abi = "o32"; 451247841Sbapt break; 452247841Sbapt case E_MIPS_ABI_N32: 453247841Sbapt abi = "n32"; 454247841Sbapt break; 455247841Sbapt default: 456247841Sbapt if (elfhdr.e_ident[EI_DATA] == 457247841Sbapt ELFCLASS32) 458247841Sbapt abi = "o32"; 459247841Sbapt else if (elfhdr.e_ident[EI_DATA] == 460247841Sbapt ELFCLASS64) 461247841Sbapt abi = "n64"; 462247841Sbapt break; 463247841Sbapt } 464255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 465255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 466255457Sbapt 467255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 468255457Sbapt arch, wordsize_corres_str, endian_corres_str, abi); 469247841Sbapt break; 470255457Sbapt default: 471255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 472255457Sbapt arch, wordsize_corres_str); 473247841Sbapt } 474247841Sbapt 475247841Sbaptcleanup: 476247841Sbapt if (elf != NULL) 477247841Sbapt elf_end(elf); 478247841Sbapt 479247841Sbapt close(fd); 480247841Sbapt return (ret); 481247841Sbapt} 482247841Sbapt 483247841Sbaptstatic void 484247841Sbaptsubst_packagesite(const char *abi) 485247841Sbapt{ 486247841Sbapt struct sbuf *newval; 487247841Sbapt const char *variable_string; 488247841Sbapt const char *oldval; 489247841Sbapt 490247841Sbapt if (c[PACKAGESITE].value != NULL) 491247841Sbapt oldval = c[PACKAGESITE].value; 492247841Sbapt else 493247841Sbapt oldval = c[PACKAGESITE].val; 494247841Sbapt 495247841Sbapt if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 496247841Sbapt return; 497247841Sbapt 498247841Sbapt newval = sbuf_new_auto(); 499247841Sbapt sbuf_bcat(newval, oldval, variable_string - oldval); 500247841Sbapt sbuf_cat(newval, abi); 501247841Sbapt sbuf_cat(newval, variable_string + strlen("${ABI}")); 502247841Sbapt sbuf_finish(newval); 503247841Sbapt 504247841Sbapt free(c[PACKAGESITE].value); 505247841Sbapt c[PACKAGESITE].value = strdup(sbuf_data(newval)); 506247841Sbapt} 507247841Sbapt 508259266Sbdrewerystatic int 509259266Sbdreweryboolstr_to_bool(const char *str) 510259266Sbdrewery{ 511259266Sbdrewery if (str != NULL && (strcasecmp(str, "true") == 0 || 512259266Sbdrewery strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 513259266Sbdrewery str[0] == '1')) 514259266Sbdrewery return (true); 515259266Sbdrewery 516259266Sbdrewery return (false); 517259266Sbdrewery} 518259266Sbdrewery 519247841Sbaptstatic void 520262400Sbaptconfig_parse(ucl_object_t *obj, pkg_conf_file_t conftype) 521247841Sbapt{ 522247841Sbapt struct sbuf *buf = sbuf_new_auto(); 523262400Sbapt ucl_object_t *cur, *seq; 524262400Sbapt ucl_object_iter_t it = NULL, itseq = NULL; 525259266Sbdrewery struct config_entry *temp_config; 526259266Sbdrewery struct config_value *cv; 527262400Sbapt const char *key; 528247841Sbapt int i; 529247841Sbapt size_t j; 530247841Sbapt 531259266Sbdrewery /* Temporary config for configs that may be disabled. */ 532259266Sbdrewery temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 533259266Sbdrewery 534262400Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 535262400Sbapt key = ucl_object_key(cur); 536262400Sbapt if (key == NULL) 537247841Sbapt continue; 538247841Sbapt sbuf_clear(buf); 539247841Sbapt 540257145Sbdrewery if (conftype == CONFFILE_PKG) { 541262400Sbapt for (j = 0; j < strlen(key); ++j) 542262400Sbapt sbuf_putc(buf, key[j]); 543257145Sbdrewery sbuf_finish(buf); 544257145Sbdrewery } else if (conftype == CONFFILE_REPO) { 545262400Sbapt if (strcasecmp(key, "url") == 0) 546257145Sbdrewery sbuf_cpy(buf, "PACKAGESITE"); 547262400Sbapt else if (strcasecmp(key, "mirror_type") == 0) 548257145Sbdrewery sbuf_cpy(buf, "MIRROR_TYPE"); 549262400Sbapt else if (strcasecmp(key, "signature_type") == 0) 550257147Sbdrewery sbuf_cpy(buf, "SIGNATURE_TYPE"); 551262400Sbapt else if (strcasecmp(key, "fingerprints") == 0) 552257147Sbdrewery sbuf_cpy(buf, "FINGERPRINTS"); 553262400Sbapt else if (strcasecmp(key, "enabled") == 0) { 554262400Sbapt if ((cur->type != UCL_BOOLEAN) || 555262400Sbapt !ucl_object_toboolean(cur)) 556259266Sbdrewery goto cleanup; 557262400Sbapt } else 558257145Sbdrewery continue; 559257145Sbdrewery sbuf_finish(buf); 560257145Sbdrewery } 561257145Sbdrewery 562247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 563247841Sbapt if (strcmp(sbuf_data(buf), c[i].key) == 0) 564247841Sbapt break; 565247841Sbapt } 566247841Sbapt 567257145Sbdrewery /* Silently skip unknown keys to be future compatible. */ 568262400Sbapt if (i == CONFIG_SIZE) 569247841Sbapt continue; 570247841Sbapt 571247841Sbapt /* env has priority over config file */ 572262400Sbapt if (c[i].envset) 573247841Sbapt continue; 574247841Sbapt 575259266Sbdrewery /* Parse sequence value ["item1", "item2"] */ 576259266Sbdrewery switch (c[i].type) { 577259266Sbdrewery case PKG_CONFIG_LIST: 578262400Sbapt if (cur->type != UCL_ARRAY) { 579262400Sbapt warnx("Skipping invalid array " 580259266Sbdrewery "value for %s.\n", c[i].key); 581259266Sbdrewery continue; 582259266Sbdrewery } 583259266Sbdrewery temp_config[i].list = 584259266Sbdrewery malloc(sizeof(*temp_config[i].list)); 585259266Sbdrewery STAILQ_INIT(temp_config[i].list); 586259266Sbdrewery 587262400Sbapt while ((seq = ucl_iterate_object(cur, &itseq, true))) { 588262400Sbapt if (seq->type != UCL_STRING) 589259266Sbdrewery continue; 590259266Sbdrewery cv = malloc(sizeof(struct config_value)); 591259266Sbdrewery cv->value = 592262400Sbapt strdup(ucl_object_tostring(seq)); 593259266Sbdrewery STAILQ_INSERT_TAIL(temp_config[i].list, cv, 594259266Sbdrewery next); 595259266Sbdrewery } 596259266Sbdrewery break; 597263181Sbdrewery case PKG_CONFIG_BOOL: 598263181Sbdrewery temp_config[i].value = 599263181Sbdrewery strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 600263181Sbdrewery break; 601259266Sbdrewery default: 602259266Sbdrewery /* Normal string value. */ 603262400Sbapt temp_config[i].value = strdup(ucl_object_tostring(cur)); 604259266Sbdrewery break; 605259266Sbdrewery } 606247841Sbapt } 607247841Sbapt 608259266Sbdrewery /* Repo is enabled, copy over all settings from temp_config. */ 609259266Sbdrewery for (i = 0; i < CONFIG_SIZE; i++) { 610259266Sbdrewery if (c[i].envset) 611259266Sbdrewery continue; 612263180Sbdrewery /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 613263180Sbdrewery if (conftype != CONFFILE_PKG && c[i].main_only == true) 614263180Sbdrewery continue; 615259266Sbdrewery switch (c[i].type) { 616259266Sbdrewery case PKG_CONFIG_LIST: 617259266Sbdrewery c[i].list = temp_config[i].list; 618259266Sbdrewery break; 619259266Sbdrewery default: 620259266Sbdrewery c[i].value = temp_config[i].value; 621259266Sbdrewery break; 622259266Sbdrewery } 623259266Sbdrewery } 624259266Sbdrewery 625259266Sbdrewerycleanup: 626259266Sbdrewery free(temp_config); 627247841Sbapt sbuf_delete(buf); 628247841Sbapt} 629247841Sbapt 630257145Sbdrewery/*- 631257145Sbdrewery * Parse new repo style configs in style: 632257145Sbdrewery * Name: 633257145Sbdrewery * URL: 634257145Sbdrewery * MIRROR_TYPE: 635257145Sbdrewery * etc... 636257145Sbdrewery */ 637257145Sbdrewerystatic void 638262400Sbaptparse_repo_file(ucl_object_t *obj) 639247841Sbapt{ 640262400Sbapt ucl_object_iter_t it = NULL; 641262400Sbapt ucl_object_t *cur; 642262400Sbapt const char *key; 643257145Sbdrewery 644262400Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 645262400Sbapt key = ucl_object_key(cur); 646257145Sbdrewery 647262400Sbapt if (key == NULL) 648257145Sbdrewery continue; 649257145Sbdrewery 650262400Sbapt if (cur->type != UCL_OBJECT) 651257145Sbdrewery continue; 652257145Sbdrewery 653262400Sbapt config_parse(cur, CONFFILE_REPO); 654257145Sbdrewery } 655257145Sbdrewery} 656257145Sbdrewery 657257145Sbdrewery 658257145Sbdrewerystatic int 659257145Sbdreweryread_conf_file(const char *confpath, pkg_conf_file_t conftype) 660257145Sbdrewery{ 661262400Sbapt struct ucl_parser *p; 662262400Sbapt ucl_object_t *obj = NULL; 663247841Sbapt 664262400Sbapt p = ucl_parser_new(0); 665262400Sbapt 666262400Sbapt if (!ucl_parser_add_file(p, confpath)) { 667247841Sbapt if (errno != ENOENT) 668262400Sbapt errx(EXIT_FAILURE, "Unable to parse configuration " 669262400Sbapt "file %s: %s", confpath, ucl_parser_get_error(p)); 670262400Sbapt ucl_parser_free(p); 671247841Sbapt /* no configuration present */ 672257145Sbdrewery return (1); 673247841Sbapt } 674247841Sbapt 675262400Sbapt obj = ucl_parser_get_object(p); 676262400Sbapt if (obj->type != UCL_OBJECT) 677257142Sbdrewery warnx("Invalid configuration format, ignoring the " 678257145Sbdrewery "configuration file %s", confpath); 679257145Sbdrewery else { 680257145Sbdrewery if (conftype == CONFFILE_PKG) 681262400Sbapt config_parse(obj, conftype); 682257145Sbdrewery else if (conftype == CONFFILE_REPO) 683262400Sbapt parse_repo_file(obj); 684247841Sbapt } 685247841Sbapt 686262400Sbapt ucl_object_free(obj); 687262400Sbapt ucl_parser_free(p); 688247841Sbapt 689257145Sbdrewery return (0); 690257145Sbdrewery} 691257145Sbdrewery 692259266Sbdrewerystatic int 693259266Sbdreweryload_repositories(const char *repodir) 694259266Sbdrewery{ 695259266Sbdrewery struct dirent *ent; 696259266Sbdrewery DIR *d; 697259266Sbdrewery char *p; 698259266Sbdrewery size_t n; 699259266Sbdrewery char path[MAXPATHLEN]; 700259266Sbdrewery int ret; 701259266Sbdrewery 702259266Sbdrewery ret = 0; 703259266Sbdrewery 704259266Sbdrewery if ((d = opendir(repodir)) == NULL) 705259266Sbdrewery return (1); 706259266Sbdrewery 707259266Sbdrewery while ((ent = readdir(d))) { 708259266Sbdrewery /* Trim out 'repos'. */ 709259266Sbdrewery if ((n = strlen(ent->d_name)) <= 5) 710259266Sbdrewery continue; 711259266Sbdrewery p = &ent->d_name[n - 5]; 712259266Sbdrewery if (strcmp(p, ".conf") == 0) { 713259266Sbdrewery snprintf(path, sizeof(path), "%s%s%s", 714259266Sbdrewery repodir, 715259266Sbdrewery repodir[strlen(repodir) - 1] == '/' ? "" : "/", 716259266Sbdrewery ent->d_name); 717259266Sbdrewery if (access(path, F_OK) == 0 && 718259266Sbdrewery read_conf_file(path, CONFFILE_REPO)) { 719259266Sbdrewery ret = 1; 720259266Sbdrewery goto cleanup; 721259266Sbdrewery } 722259266Sbdrewery } 723259266Sbdrewery } 724259266Sbdrewery 725259266Sbdrewerycleanup: 726259266Sbdrewery closedir(d); 727259266Sbdrewery 728259266Sbdrewery return (ret); 729259266Sbdrewery} 730259266Sbdrewery 731257145Sbdreweryint 732257145Sbdreweryconfig_init(void) 733257145Sbdrewery{ 734259266Sbdrewery char *val; 735257145Sbdrewery int i; 736257145Sbdrewery const char *localbase; 737259266Sbdrewery char *env_list_item; 738257145Sbdrewery char confpath[MAXPATHLEN]; 739259266Sbdrewery struct config_value *cv; 740257145Sbdrewery char abi[BUFSIZ]; 741257145Sbdrewery 742257145Sbdrewery for (i = 0; i < CONFIG_SIZE; i++) { 743257145Sbdrewery val = getenv(c[i].key); 744257145Sbdrewery if (val != NULL) { 745257145Sbdrewery c[i].envset = true; 746259266Sbdrewery switch (c[i].type) { 747259266Sbdrewery case PKG_CONFIG_LIST: 748259266Sbdrewery /* Split up comma-separated items from env. */ 749259266Sbdrewery c[i].list = malloc(sizeof(*c[i].list)); 750259266Sbdrewery STAILQ_INIT(c[i].list); 751259266Sbdrewery for (env_list_item = strtok(val, ","); 752259266Sbdrewery env_list_item != NULL; 753259266Sbdrewery env_list_item = strtok(NULL, ",")) { 754259266Sbdrewery cv = 755259266Sbdrewery malloc(sizeof(struct config_value)); 756259266Sbdrewery cv->value = 757259266Sbdrewery strdup(env_list_item); 758259266Sbdrewery STAILQ_INSERT_TAIL(c[i].list, cv, 759259266Sbdrewery next); 760259266Sbdrewery } 761259266Sbdrewery break; 762259266Sbdrewery default: 763259266Sbdrewery c[i].val = val; 764259266Sbdrewery break; 765259266Sbdrewery } 766257145Sbdrewery } 767257145Sbdrewery } 768257145Sbdrewery 769259266Sbdrewery /* Read LOCALBASE/etc/pkg.conf first. */ 770257145Sbdrewery localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 771257145Sbdrewery snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 772257145Sbdrewery localbase); 773257145Sbdrewery 774257145Sbdrewery if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 775257145Sbdrewery CONFFILE_PKG)) 776257145Sbdrewery goto finalize; 777257145Sbdrewery 778259266Sbdrewery /* Then read in all repos from REPOS_DIR list of directories. */ 779259266Sbdrewery if (c[REPOS_DIR].list == NULL) { 780259266Sbdrewery c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 781259266Sbdrewery STAILQ_INIT(c[REPOS_DIR].list); 782259266Sbdrewery cv = malloc(sizeof(struct config_value)); 783259266Sbdrewery cv->value = strdup("/etc/pkg"); 784259266Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 785259266Sbdrewery cv = malloc(sizeof(struct config_value)); 786259266Sbdrewery if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 787259266Sbdrewery goto finalize; 788259266Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 789259266Sbdrewery } 790257145Sbdrewery 791259266Sbdrewery STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 792259266Sbdrewery if (load_repositories(cv->value)) 793259266Sbdrewery goto finalize; 794259266Sbdrewery 795247841Sbaptfinalize: 796247841Sbapt if (c[ABI].val == NULL && c[ABI].value == NULL) { 797247841Sbapt if (pkg_get_myabi(abi, BUFSIZ) != 0) 798257142Sbdrewery errx(EXIT_FAILURE, "Failed to determine the system " 799257142Sbdrewery "ABI"); 800247841Sbapt c[ABI].val = abi; 801247841Sbapt } 802247841Sbapt 803247843Sbapt subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 804247841Sbapt 805247841Sbapt return (0); 806247841Sbapt} 807247841Sbapt 808247841Sbaptint 809247841Sbaptconfig_string(pkg_config_key k, const char **val) 810247841Sbapt{ 811247841Sbapt if (c[k].type != PKG_CONFIG_STRING) 812247841Sbapt return (-1); 813247841Sbapt 814247841Sbapt if (c[k].value != NULL) 815247841Sbapt *val = c[k].value; 816247841Sbapt else 817247841Sbapt *val = c[k].val; 818247841Sbapt 819247841Sbapt return (0); 820247841Sbapt} 821247841Sbapt 822247841Sbaptint 823247841Sbaptconfig_bool(pkg_config_key k, bool *val) 824247841Sbapt{ 825247841Sbapt const char *value; 826247841Sbapt 827247841Sbapt if (c[k].type != PKG_CONFIG_BOOL) 828247841Sbapt return (-1); 829247841Sbapt 830247841Sbapt *val = false; 831247841Sbapt 832247841Sbapt if (c[k].value != NULL) 833247841Sbapt value = c[k].value; 834247841Sbapt else 835247841Sbapt value = c[k].val; 836247841Sbapt 837259266Sbdrewery if (boolstr_to_bool(value)) 838247841Sbapt *val = true; 839247841Sbapt 840247841Sbapt return (0); 841247841Sbapt} 842247841Sbapt 843247841Sbaptvoid 844247841Sbaptconfig_finish(void) { 845247841Sbapt int i; 846247841Sbapt 847247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) 848247841Sbapt free(c[i].value); 849247841Sbapt} 850