1247841Sbapt/*- 2263020Sbapt * Copyright (c) 2014 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$"); 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> 40263020Sbapt#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 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; 69263621Sbdrewery bool main_only; /* Only set in pkg.conf. */ 70247841Sbapt}; 71247841Sbapt 72247841Sbaptstatic struct config_entry c[] = { 73247841Sbapt [PACKAGESITE] = { 74247841Sbapt PKG_CONFIG_STRING, 75247841Sbapt "PACKAGESITE", 76257328Sbdrewery URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 77247841Sbapt NULL, 78259613Sbdrewery NULL, 79247841Sbapt false, 80263621Sbdrewery false, 81247841Sbapt }, 82247841Sbapt [ABI] = { 83247841Sbapt PKG_CONFIG_STRING, 84247841Sbapt "ABI", 85247841Sbapt NULL, 86247841Sbapt NULL, 87259613Sbdrewery NULL, 88247841Sbapt false, 89263621Sbdrewery true, 90247841Sbapt }, 91247841Sbapt [MIRROR_TYPE] = { 92247841Sbapt PKG_CONFIG_STRING, 93247841Sbapt "MIRROR_TYPE", 94247841Sbapt "SRV", 95247841Sbapt NULL, 96259613Sbdrewery NULL, 97247841Sbapt false, 98263621Sbdrewery false, 99247841Sbapt }, 100247841Sbapt [ASSUME_ALWAYS_YES] = { 101247841Sbapt PKG_CONFIG_BOOL, 102247841Sbapt "ASSUME_ALWAYS_YES", 103247841Sbapt "NO", 104247841Sbapt NULL, 105259613Sbdrewery NULL, 106247841Sbapt false, 107263621Sbdrewery true, 108257353Sbdrewery }, 109257353Sbdrewery [SIGNATURE_TYPE] = { 110257353Sbdrewery PKG_CONFIG_STRING, 111257353Sbdrewery "SIGNATURE_TYPE", 112257353Sbdrewery NULL, 113257353Sbdrewery NULL, 114259613Sbdrewery NULL, 115257353Sbdrewery false, 116263621Sbdrewery false, 117257353Sbdrewery }, 118257353Sbdrewery [FINGERPRINTS] = { 119257353Sbdrewery PKG_CONFIG_STRING, 120257353Sbdrewery "FINGERPRINTS", 121257353Sbdrewery NULL, 122257353Sbdrewery NULL, 123259613Sbdrewery NULL, 124257353Sbdrewery false, 125263621Sbdrewery false, 126257353Sbdrewery }, 127259613Sbdrewery [REPOS_DIR] = { 128259613Sbdrewery PKG_CONFIG_LIST, 129259613Sbdrewery "REPOS_DIR", 130259613Sbdrewery NULL, 131259613Sbdrewery NULL, 132259613Sbdrewery NULL, 133259613Sbdrewery false, 134263621Sbdrewery true, 135259613Sbdrewery }, 136287873Sdelphij [PUBKEY] = { 137287873Sdelphij PKG_CONFIG_STRING, 138287873Sdelphij "PUBKEY", 139287873Sdelphij NULL, 140287873Sdelphij NULL, 141287873Sdelphij NULL, 142287873Sdelphij false, 143287873Sdelphij false 144287873Sdelphij } 145247841Sbapt}; 146247841Sbapt 147247841Sbaptstatic const char * 148247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e) 149247841Sbapt{ 150247841Sbapt int i; 151247841Sbapt 152247841Sbapt for (i = 0; m[i].string != NULL; i++) 153247841Sbapt if (m[i].elf_nb == e) 154247841Sbapt return (m[i].string); 155247841Sbapt 156247841Sbapt return ("unknown"); 157247841Sbapt} 158247841Sbapt 159255457Sbaptstatic const char * 160255457Sbaptaeabi_parse_arm_attributes(void *data, size_t length) 161255457Sbapt{ 162255457Sbapt uint32_t sect_len; 163255457Sbapt uint8_t *section = data; 164255457Sbapt 165255457Sbapt#define MOVE(len) do { \ 166255457Sbapt assert(length >= (len)); \ 167255457Sbapt section += (len); \ 168255457Sbapt length -= (len); \ 169255457Sbapt} while (0) 170255457Sbapt 171255457Sbapt if (length == 0 || *section != 'A') 172255457Sbapt return (NULL); 173255457Sbapt 174255457Sbapt MOVE(1); 175255457Sbapt 176255457Sbapt /* Read the section length */ 177255457Sbapt if (length < sizeof(sect_len)) 178255457Sbapt return (NULL); 179255457Sbapt 180255457Sbapt memcpy(§_len, section, sizeof(sect_len)); 181255457Sbapt 182255457Sbapt /* 183255457Sbapt * The section length should be no longer than the section it is within 184255457Sbapt */ 185255457Sbapt if (sect_len > length) 186255457Sbapt return (NULL); 187255457Sbapt 188255457Sbapt MOVE(sizeof(sect_len)); 189255457Sbapt 190255457Sbapt /* Skip the vendor name */ 191255457Sbapt while (length != 0) { 192255457Sbapt if (*section == '\0') 193255457Sbapt break; 194255457Sbapt MOVE(1); 195255457Sbapt } 196255457Sbapt if (length == 0) 197255457Sbapt return (NULL); 198255457Sbapt MOVE(1); 199255457Sbapt 200255457Sbapt while (length != 0) { 201255457Sbapt uint32_t tag_length; 202255457Sbapt 203255457Sbapt switch(*section) { 204255457Sbapt case 1: /* Tag_File */ 205255457Sbapt MOVE(1); 206255457Sbapt if (length < sizeof(tag_length)) 207255457Sbapt return (NULL); 208255457Sbapt memcpy(&tag_length, section, sizeof(tag_length)); 209255457Sbapt break; 210255457Sbapt case 2: /* Tag_Section */ 211255457Sbapt case 3: /* Tag_Symbol */ 212255457Sbapt default: 213255457Sbapt return (NULL); 214255457Sbapt } 215255457Sbapt /* At least space for the tag and size */ 216255457Sbapt if (tag_length <= 5) 217255457Sbapt return (NULL); 218255457Sbapt tag_length--; 219255457Sbapt /* Check the tag fits */ 220255457Sbapt if (tag_length > length) 221255457Sbapt return (NULL); 222255457Sbapt 223255457Sbapt#define MOVE_TAG(len) do { \ 224255457Sbapt assert(tag_length >= (len)); \ 225255457Sbapt MOVE(len); \ 226255457Sbapt tag_length -= (len); \ 227255457Sbapt} while(0) 228255457Sbapt 229255457Sbapt MOVE(sizeof(tag_length)); 230255457Sbapt tag_length -= sizeof(tag_length); 231255457Sbapt 232255457Sbapt while (tag_length != 0) { 233255457Sbapt uint8_t tag; 234255457Sbapt 235255457Sbapt assert(tag_length >= length); 236255457Sbapt 237255457Sbapt tag = *section; 238255457Sbapt MOVE_TAG(1); 239255457Sbapt 240255457Sbapt /* 241255457Sbapt * These tag values come from: 242255457Sbapt * 243255457Sbapt * Addenda to, and Errata in, the ABI for the 244255457Sbapt * ARM Architecture. Release 2.08, section 2.3. 245255457Sbapt */ 246255457Sbapt if (tag == 6) { /* == Tag_CPU_arch */ 247255457Sbapt uint8_t val; 248255457Sbapt 249255457Sbapt val = *section; 250255457Sbapt /* 251255457Sbapt * We don't support values that require 252255457Sbapt * more than one byte. 253255457Sbapt */ 254255457Sbapt if (val & (1 << 7)) 255255457Sbapt return (NULL); 256255457Sbapt 257255457Sbapt /* We have an ARMv4 or ARMv5 */ 258255457Sbapt if (val <= 5) 259255457Sbapt return ("arm"); 260255457Sbapt else /* We have an ARMv6+ */ 261255457Sbapt return ("armv6"); 262255457Sbapt } else if (tag == 4 || tag == 5 || tag == 32 || 263255457Sbapt tag == 65 || tag == 67) { 264255457Sbapt while (*section != '\0' && length != 0) 265255457Sbapt MOVE_TAG(1); 266255457Sbapt if (tag_length == 0) 267255457Sbapt return (NULL); 268255457Sbapt /* Skip the last byte */ 269255457Sbapt MOVE_TAG(1); 270255457Sbapt } else if ((tag >= 7 && tag <= 31) || tag == 34 || 271255457Sbapt tag == 36 || tag == 38 || tag == 42 || tag == 44 || 272255457Sbapt tag == 64 || tag == 66 || tag == 68 || tag == 70) { 273255457Sbapt /* Skip the uleb128 data */ 274255457Sbapt while (*section & (1 << 7) && length != 0) 275255457Sbapt MOVE_TAG(1); 276255457Sbapt if (tag_length == 0) 277255457Sbapt return (NULL); 278255457Sbapt /* Skip the last byte */ 279255457Sbapt MOVE_TAG(1); 280255457Sbapt } else 281255457Sbapt return (NULL); 282255457Sbapt#undef MOVE_TAG 283255457Sbapt } 284255457Sbapt 285255457Sbapt break; 286255457Sbapt } 287255457Sbapt return (NULL); 288255457Sbapt#undef MOVE 289255457Sbapt} 290255457Sbapt 291247841Sbaptstatic int 292247841Sbaptpkg_get_myabi(char *dest, size_t sz) 293247841Sbapt{ 294247841Sbapt Elf *elf; 295247841Sbapt Elf_Data *data; 296247841Sbapt Elf_Note note; 297247841Sbapt Elf_Scn *scn; 298247841Sbapt char *src, *osname; 299255457Sbapt const char *arch, *abi, *fpu, *endian_corres_str; 300255457Sbapt const char *wordsize_corres_str; 301247841Sbapt GElf_Ehdr elfhdr; 302247841Sbapt GElf_Shdr shdr; 303247841Sbapt int fd, i, ret; 304247841Sbapt uint32_t version; 305247841Sbapt 306247841Sbapt version = 0; 307247841Sbapt ret = -1; 308247841Sbapt scn = NULL; 309247841Sbapt abi = NULL; 310247841Sbapt 311247841Sbapt if (elf_version(EV_CURRENT) == EV_NONE) { 312247841Sbapt warnx("ELF library initialization failed: %s", 313247841Sbapt elf_errmsg(-1)); 314247841Sbapt return (-1); 315247841Sbapt } 316247841Sbapt 317247841Sbapt if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) { 318247841Sbapt warn("open()"); 319247841Sbapt return (-1); 320247841Sbapt } 321247841Sbapt 322247841Sbapt if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) { 323247841Sbapt ret = -1; 324247841Sbapt warnx("elf_begin() failed: %s.", elf_errmsg(-1)); 325247841Sbapt goto cleanup; 326247841Sbapt } 327247841Sbapt 328247841Sbapt if (gelf_getehdr(elf, &elfhdr) == NULL) { 329247841Sbapt ret = -1; 330247841Sbapt warn("getehdr() failed: %s.", elf_errmsg(-1)); 331247841Sbapt goto cleanup; 332247841Sbapt } 333247841Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 334247841Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 335247841Sbapt ret = -1; 336247841Sbapt warn("getshdr() failed: %s.", elf_errmsg(-1)); 337247841Sbapt goto cleanup; 338247841Sbapt } 339247841Sbapt 340247841Sbapt if (shdr.sh_type == SHT_NOTE) 341247841Sbapt break; 342247841Sbapt } 343247841Sbapt 344247841Sbapt if (scn == NULL) { 345247841Sbapt ret = -1; 346247841Sbapt warn("failed to get the note section"); 347247841Sbapt goto cleanup; 348247841Sbapt } 349247841Sbapt 350247841Sbapt data = elf_getdata(scn, NULL); 351247841Sbapt src = data->d_buf; 352247841Sbapt for (;;) { 353247841Sbapt memcpy(¬e, src, sizeof(Elf_Note)); 354247841Sbapt src += sizeof(Elf_Note); 355247841Sbapt if (note.n_type == NT_VERSION) 356247841Sbapt break; 357247841Sbapt src += note.n_namesz + note.n_descsz; 358247841Sbapt } 359247841Sbapt osname = src; 360247841Sbapt src += roundup2(note.n_namesz, 4); 361247841Sbapt if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB) 362247841Sbapt version = be32dec(src); 363247841Sbapt else 364247841Sbapt version = le32dec(src); 365247841Sbapt 366247841Sbapt for (i = 0; osname[i] != '\0'; i++) 367247841Sbapt osname[i] = (char)tolower(osname[i]); 368247841Sbapt 369255457Sbapt wordsize_corres_str = elf_corres_to_string(wordsize_corres, 370255457Sbapt (int)elfhdr.e_ident[EI_CLASS]); 371247841Sbapt 372255457Sbapt arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine); 373255457Sbapt 374255457Sbapt snprintf(dest, sz, "%s:%d", 375255457Sbapt osname, version / 100000); 376255457Sbapt 377247841Sbapt ret = 0; 378247841Sbapt 379247841Sbapt switch (elfhdr.e_machine) { 380247841Sbapt case EM_ARM: 381255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 382255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 383255457Sbapt 384253755Sbapt /* FreeBSD doesn't support the hard-float ABI yet */ 385253755Sbapt fpu = "softfp"; 386253755Sbapt if ((elfhdr.e_flags & 0xFF000000) != 0) { 387255457Sbapt const char *sh_name = NULL; 388255457Sbapt size_t shstrndx; 389255457Sbapt 390253755Sbapt /* This is an EABI file, the conformance level is set */ 391253755Sbapt abi = "eabi"; 392255457Sbapt /* Find which TARGET_ARCH we are building for. */ 393255457Sbapt elf_getshdrstrndx(elf, &shstrndx); 394255457Sbapt while ((scn = elf_nextscn(elf, scn)) != NULL) { 395255457Sbapt sh_name = NULL; 396255457Sbapt if (gelf_getshdr(scn, &shdr) != &shdr) { 397255457Sbapt scn = NULL; 398255457Sbapt break; 399255457Sbapt } 400255457Sbapt 401255457Sbapt sh_name = elf_strptr(elf, shstrndx, 402255457Sbapt shdr.sh_name); 403255457Sbapt if (sh_name == NULL) 404255457Sbapt continue; 405255457Sbapt if (strcmp(".ARM.attributes", sh_name) == 0) 406255457Sbapt break; 407255457Sbapt } 408255457Sbapt if (scn != NULL && sh_name != NULL) { 409255457Sbapt data = elf_getdata(scn, NULL); 410255457Sbapt /* 411255457Sbapt * Prior to FreeBSD 10.0 libelf would return 412255457Sbapt * NULL from elf_getdata on the .ARM.attributes 413255457Sbapt * section. As this was the first release to 414255457Sbapt * get armv6 support assume a NULL value means 415255457Sbapt * arm. 416255457Sbapt * 417255457Sbapt * This assumption can be removed when 9.x 418255457Sbapt * is unsupported. 419255457Sbapt */ 420255457Sbapt if (data != NULL) { 421255457Sbapt arch = aeabi_parse_arm_attributes( 422255457Sbapt data->d_buf, data->d_size); 423255457Sbapt if (arch == NULL) { 424255457Sbapt ret = 1; 425255457Sbapt warn("unknown ARM ARCH"); 426255457Sbapt goto cleanup; 427255457Sbapt } 428255457Sbapt } 429255457Sbapt } else { 430255457Sbapt ret = 1; 431255457Sbapt warn("Unable to find the .ARM.attributes " 432255457Sbapt "section"); 433255457Sbapt goto cleanup; 434255457Sbapt } 435253755Sbapt } else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) { 436253755Sbapt /* 437253755Sbapt * EABI executables all have this field set to 438253755Sbapt * ELFOSABI_NONE, therefore it must be an oabi file. 439253755Sbapt */ 440253755Sbapt abi = "oabi"; 441253755Sbapt } else { 442253755Sbapt ret = 1; 443255457Sbapt warn("unknown ARM ABI"); 444253755Sbapt goto cleanup; 445253755Sbapt } 446247841Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), 447255457Sbapt ":%s:%s:%s:%s:%s", arch, wordsize_corres_str, 448255457Sbapt endian_corres_str, abi, fpu); 449247841Sbapt break; 450247841Sbapt case EM_MIPS: 451247841Sbapt /* 452247841Sbapt * this is taken from binutils sources: 453247841Sbapt * include/elf/mips.h 454247841Sbapt * mapping is figured out from binutils: 455247841Sbapt * gas/config/tc-mips.c 456247841Sbapt */ 457247841Sbapt switch (elfhdr.e_flags & EF_MIPS_ABI) { 458247841Sbapt case E_MIPS_ABI_O32: 459247841Sbapt abi = "o32"; 460247841Sbapt break; 461247841Sbapt case E_MIPS_ABI_N32: 462247841Sbapt abi = "n32"; 463247841Sbapt break; 464247841Sbapt default: 465247841Sbapt if (elfhdr.e_ident[EI_DATA] == 466247841Sbapt ELFCLASS32) 467247841Sbapt abi = "o32"; 468247841Sbapt else if (elfhdr.e_ident[EI_DATA] == 469247841Sbapt ELFCLASS64) 470247841Sbapt abi = "n64"; 471247841Sbapt break; 472247841Sbapt } 473255457Sbapt endian_corres_str = elf_corres_to_string(endian_corres, 474255457Sbapt (int)elfhdr.e_ident[EI_DATA]); 475255457Sbapt 476255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s:%s:%s", 477255457Sbapt arch, wordsize_corres_str, endian_corres_str, abi); 478247841Sbapt break; 479255457Sbapt default: 480255457Sbapt snprintf(dest + strlen(dest), sz - strlen(dest), ":%s:%s", 481255457Sbapt arch, wordsize_corres_str); 482247841Sbapt } 483247841Sbapt 484247841Sbaptcleanup: 485247841Sbapt if (elf != NULL) 486247841Sbapt elf_end(elf); 487247841Sbapt 488247841Sbapt close(fd); 489247841Sbapt return (ret); 490247841Sbapt} 491247841Sbapt 492247841Sbaptstatic void 493247841Sbaptsubst_packagesite(const char *abi) 494247841Sbapt{ 495247841Sbapt struct sbuf *newval; 496247841Sbapt const char *variable_string; 497247841Sbapt const char *oldval; 498247841Sbapt 499247841Sbapt if (c[PACKAGESITE].value != NULL) 500247841Sbapt oldval = c[PACKAGESITE].value; 501247841Sbapt else 502247841Sbapt oldval = c[PACKAGESITE].val; 503247841Sbapt 504247841Sbapt if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 505247841Sbapt return; 506247841Sbapt 507247841Sbapt newval = sbuf_new_auto(); 508247841Sbapt sbuf_bcat(newval, oldval, variable_string - oldval); 509247841Sbapt sbuf_cat(newval, abi); 510247841Sbapt sbuf_cat(newval, variable_string + strlen("${ABI}")); 511247841Sbapt sbuf_finish(newval); 512247841Sbapt 513247841Sbapt free(c[PACKAGESITE].value); 514247841Sbapt c[PACKAGESITE].value = strdup(sbuf_data(newval)); 515247841Sbapt} 516247841Sbapt 517259613Sbdrewerystatic int 518259613Sbdreweryboolstr_to_bool(const char *str) 519259613Sbdrewery{ 520259613Sbdrewery if (str != NULL && (strcasecmp(str, "true") == 0 || 521259613Sbdrewery strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 522259613Sbdrewery str[0] == '1')) 523259613Sbdrewery return (true); 524259613Sbdrewery 525259613Sbdrewery return (false); 526259613Sbdrewery} 527259613Sbdrewery 528247841Sbaptstatic void 529268896Sbaptconfig_parse(const ucl_object_t *obj, pkg_conf_file_t conftype) 530247841Sbapt{ 531247841Sbapt struct sbuf *buf = sbuf_new_auto(); 532268896Sbapt const ucl_object_t *cur, *seq; 533263020Sbapt ucl_object_iter_t it = NULL, itseq = NULL; 534259613Sbdrewery struct config_entry *temp_config; 535259613Sbdrewery struct config_value *cv; 536263020Sbapt const char *key; 537247841Sbapt int i; 538247841Sbapt size_t j; 539247841Sbapt 540259613Sbdrewery /* Temporary config for configs that may be disabled. */ 541259613Sbdrewery temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 542259613Sbdrewery 543263020Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 544263020Sbapt key = ucl_object_key(cur); 545263020Sbapt if (key == NULL) 546247841Sbapt continue; 547247841Sbapt sbuf_clear(buf); 548247841Sbapt 549257353Sbdrewery if (conftype == CONFFILE_PKG) { 550263020Sbapt for (j = 0; j < strlen(key); ++j) 551263020Sbapt sbuf_putc(buf, key[j]); 552257353Sbdrewery sbuf_finish(buf); 553257353Sbdrewery } else if (conftype == CONFFILE_REPO) { 554263020Sbapt if (strcasecmp(key, "url") == 0) 555257353Sbdrewery sbuf_cpy(buf, "PACKAGESITE"); 556263020Sbapt else if (strcasecmp(key, "mirror_type") == 0) 557257353Sbdrewery sbuf_cpy(buf, "MIRROR_TYPE"); 558263020Sbapt else if (strcasecmp(key, "signature_type") == 0) 559257353Sbdrewery sbuf_cpy(buf, "SIGNATURE_TYPE"); 560263020Sbapt else if (strcasecmp(key, "fingerprints") == 0) 561257353Sbdrewery sbuf_cpy(buf, "FINGERPRINTS"); 562287873Sdelphij else if (strcasecmp(key, "pubkey") == 0) 563287873Sdelphij sbuf_cpy(buf, "PUBKEY"); 564263020Sbapt else if (strcasecmp(key, "enabled") == 0) { 565263020Sbapt if ((cur->type != UCL_BOOLEAN) || 566263020Sbapt !ucl_object_toboolean(cur)) 567259613Sbdrewery goto cleanup; 568263020Sbapt } else 569257353Sbdrewery continue; 570257353Sbdrewery sbuf_finish(buf); 571257353Sbdrewery } 572257353Sbdrewery 573247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 574247841Sbapt if (strcmp(sbuf_data(buf), c[i].key) == 0) 575247841Sbapt break; 576247841Sbapt } 577247841Sbapt 578257353Sbdrewery /* Silently skip unknown keys to be future compatible. */ 579263020Sbapt if (i == CONFIG_SIZE) 580247841Sbapt continue; 581247841Sbapt 582247841Sbapt /* env has priority over config file */ 583263020Sbapt if (c[i].envset) 584247841Sbapt continue; 585247841Sbapt 586259613Sbdrewery /* Parse sequence value ["item1", "item2"] */ 587259613Sbdrewery switch (c[i].type) { 588259613Sbdrewery case PKG_CONFIG_LIST: 589263020Sbapt if (cur->type != UCL_ARRAY) { 590263020Sbapt warnx("Skipping invalid array " 591259613Sbdrewery "value for %s.\n", c[i].key); 592259613Sbdrewery continue; 593259613Sbdrewery } 594259613Sbdrewery temp_config[i].list = 595259613Sbdrewery malloc(sizeof(*temp_config[i].list)); 596259613Sbdrewery STAILQ_INIT(temp_config[i].list); 597259613Sbdrewery 598263020Sbapt while ((seq = ucl_iterate_object(cur, &itseq, true))) { 599263020Sbapt if (seq->type != UCL_STRING) 600259613Sbdrewery continue; 601259613Sbdrewery cv = malloc(sizeof(struct config_value)); 602259613Sbdrewery cv->value = 603263020Sbapt strdup(ucl_object_tostring(seq)); 604259613Sbdrewery STAILQ_INSERT_TAIL(temp_config[i].list, cv, 605259613Sbdrewery next); 606259613Sbdrewery } 607259613Sbdrewery break; 608263624Sbdrewery case PKG_CONFIG_BOOL: 609263624Sbdrewery temp_config[i].value = 610263624Sbdrewery strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 611263624Sbdrewery break; 612259613Sbdrewery default: 613259613Sbdrewery /* Normal string value. */ 614263020Sbapt temp_config[i].value = strdup(ucl_object_tostring(cur)); 615259613Sbdrewery break; 616259613Sbdrewery } 617247841Sbapt } 618247841Sbapt 619259613Sbdrewery /* Repo is enabled, copy over all settings from temp_config. */ 620259613Sbdrewery for (i = 0; i < CONFIG_SIZE; i++) { 621259613Sbdrewery if (c[i].envset) 622259613Sbdrewery continue; 623263621Sbdrewery /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 624263621Sbdrewery if (conftype != CONFFILE_PKG && c[i].main_only == true) 625263621Sbdrewery continue; 626259613Sbdrewery switch (c[i].type) { 627259613Sbdrewery case PKG_CONFIG_LIST: 628259613Sbdrewery c[i].list = temp_config[i].list; 629259613Sbdrewery break; 630259613Sbdrewery default: 631259613Sbdrewery c[i].value = temp_config[i].value; 632259613Sbdrewery break; 633259613Sbdrewery } 634259613Sbdrewery } 635259613Sbdrewery 636259613Sbdrewerycleanup: 637259613Sbdrewery free(temp_config); 638247841Sbapt sbuf_delete(buf); 639247841Sbapt} 640247841Sbapt 641257353Sbdrewery/*- 642257353Sbdrewery * Parse new repo style configs in style: 643257353Sbdrewery * Name: 644257353Sbdrewery * URL: 645257353Sbdrewery * MIRROR_TYPE: 646257353Sbdrewery * etc... 647257353Sbdrewery */ 648257353Sbdrewerystatic void 649263020Sbaptparse_repo_file(ucl_object_t *obj) 650247841Sbapt{ 651263020Sbapt ucl_object_iter_t it = NULL; 652268896Sbapt const ucl_object_t *cur; 653263020Sbapt const char *key; 654257353Sbdrewery 655263020Sbapt while ((cur = ucl_iterate_object(obj, &it, true))) { 656263020Sbapt key = ucl_object_key(cur); 657257353Sbdrewery 658263020Sbapt if (key == NULL) 659257353Sbdrewery continue; 660257353Sbdrewery 661263020Sbapt if (cur->type != UCL_OBJECT) 662257353Sbdrewery continue; 663257353Sbdrewery 664263020Sbapt config_parse(cur, CONFFILE_REPO); 665257353Sbdrewery } 666257353Sbdrewery} 667257353Sbdrewery 668257353Sbdrewery 669257353Sbdrewerystatic int 670257353Sbdreweryread_conf_file(const char *confpath, pkg_conf_file_t conftype) 671257353Sbdrewery{ 672263020Sbapt struct ucl_parser *p; 673263020Sbapt ucl_object_t *obj = NULL; 674257353Sbdrewery 675263020Sbapt p = ucl_parser_new(0); 676263020Sbapt 677263020Sbapt if (!ucl_parser_add_file(p, confpath)) { 678257353Sbdrewery if (errno != ENOENT) 679263020Sbapt errx(EXIT_FAILURE, "Unable to parse configuration " 680263020Sbapt "file %s: %s", confpath, ucl_parser_get_error(p)); 681263020Sbapt ucl_parser_free(p); 682257353Sbdrewery /* no configuration present */ 683257353Sbdrewery return (1); 684257353Sbdrewery } 685257353Sbdrewery 686263020Sbapt obj = ucl_parser_get_object(p); 687263020Sbapt if (obj->type != UCL_OBJECT) 688257353Sbdrewery warnx("Invalid configuration format, ignoring the " 689257353Sbdrewery "configuration file %s", confpath); 690257353Sbdrewery else { 691257353Sbdrewery if (conftype == CONFFILE_PKG) 692263020Sbapt config_parse(obj, conftype); 693257353Sbdrewery else if (conftype == CONFFILE_REPO) 694263020Sbapt parse_repo_file(obj); 695257353Sbdrewery } 696257353Sbdrewery 697268896Sbapt ucl_object_unref(obj); 698263020Sbapt ucl_parser_free(p); 699257353Sbdrewery 700257353Sbdrewery return (0); 701257353Sbdrewery} 702257353Sbdrewery 703259613Sbdrewerystatic int 704259613Sbdreweryload_repositories(const char *repodir) 705259613Sbdrewery{ 706259613Sbdrewery struct dirent *ent; 707259613Sbdrewery DIR *d; 708259613Sbdrewery char *p; 709259613Sbdrewery size_t n; 710259613Sbdrewery char path[MAXPATHLEN]; 711259613Sbdrewery int ret; 712259613Sbdrewery 713259613Sbdrewery ret = 0; 714259613Sbdrewery 715259613Sbdrewery if ((d = opendir(repodir)) == NULL) 716259613Sbdrewery return (1); 717259613Sbdrewery 718259613Sbdrewery while ((ent = readdir(d))) { 719259613Sbdrewery /* Trim out 'repos'. */ 720259613Sbdrewery if ((n = strlen(ent->d_name)) <= 5) 721259613Sbdrewery continue; 722259613Sbdrewery p = &ent->d_name[n - 5]; 723259613Sbdrewery if (strcmp(p, ".conf") == 0) { 724259613Sbdrewery snprintf(path, sizeof(path), "%s%s%s", 725259613Sbdrewery repodir, 726259613Sbdrewery repodir[strlen(repodir) - 1] == '/' ? "" : "/", 727259613Sbdrewery ent->d_name); 728259613Sbdrewery if (access(path, F_OK) == 0 && 729259613Sbdrewery read_conf_file(path, CONFFILE_REPO)) { 730259613Sbdrewery ret = 1; 731259613Sbdrewery goto cleanup; 732259613Sbdrewery } 733259613Sbdrewery } 734259613Sbdrewery } 735259613Sbdrewery 736259613Sbdrewerycleanup: 737259613Sbdrewery closedir(d); 738259613Sbdrewery 739259613Sbdrewery return (ret); 740259613Sbdrewery} 741259613Sbdrewery 742257353Sbdreweryint 743257353Sbdreweryconfig_init(void) 744257353Sbdrewery{ 745259613Sbdrewery char *val; 746247841Sbapt int i; 747247841Sbapt const char *localbase; 748259613Sbdrewery char *env_list_item; 749247841Sbapt char confpath[MAXPATHLEN]; 750259613Sbdrewery struct config_value *cv; 751247841Sbapt char abi[BUFSIZ]; 752247841Sbapt 753247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) { 754247841Sbapt val = getenv(c[i].key); 755247841Sbapt if (val != NULL) { 756247841Sbapt c[i].envset = true; 757259613Sbdrewery switch (c[i].type) { 758259613Sbdrewery case PKG_CONFIG_LIST: 759259613Sbdrewery /* Split up comma-separated items from env. */ 760259613Sbdrewery c[i].list = malloc(sizeof(*c[i].list)); 761259613Sbdrewery STAILQ_INIT(c[i].list); 762259613Sbdrewery for (env_list_item = strtok(val, ","); 763259613Sbdrewery env_list_item != NULL; 764259613Sbdrewery env_list_item = strtok(NULL, ",")) { 765259613Sbdrewery cv = 766259613Sbdrewery malloc(sizeof(struct config_value)); 767259613Sbdrewery cv->value = 768259613Sbdrewery strdup(env_list_item); 769259613Sbdrewery STAILQ_INSERT_TAIL(c[i].list, cv, 770259613Sbdrewery next); 771259613Sbdrewery } 772259613Sbdrewery break; 773259613Sbdrewery default: 774259613Sbdrewery c[i].val = val; 775259613Sbdrewery break; 776259613Sbdrewery } 777247841Sbapt } 778247841Sbapt } 779247841Sbapt 780259613Sbdrewery /* Read LOCALBASE/etc/pkg.conf first. */ 781247841Sbapt localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE; 782257353Sbdrewery snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", 783257353Sbdrewery localbase); 784247841Sbapt 785257353Sbdrewery if (access(confpath, F_OK) == 0 && read_conf_file(confpath, 786257353Sbdrewery CONFFILE_PKG)) 787247841Sbapt goto finalize; 788247841Sbapt 789259613Sbdrewery /* Then read in all repos from REPOS_DIR list of directories. */ 790259613Sbdrewery if (c[REPOS_DIR].list == NULL) { 791259613Sbdrewery c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 792259613Sbdrewery STAILQ_INIT(c[REPOS_DIR].list); 793259613Sbdrewery cv = malloc(sizeof(struct config_value)); 794259613Sbdrewery cv->value = strdup("/etc/pkg"); 795259613Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 796259613Sbdrewery cv = malloc(sizeof(struct config_value)); 797259613Sbdrewery if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 798259613Sbdrewery goto finalize; 799259613Sbdrewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 800259613Sbdrewery } 801247841Sbapt 802259613Sbdrewery STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 803259613Sbdrewery if (load_repositories(cv->value)) 804259613Sbdrewery goto finalize; 805259613Sbdrewery 806247841Sbaptfinalize: 807247841Sbapt if (c[ABI].val == NULL && c[ABI].value == NULL) { 808247841Sbapt if (pkg_get_myabi(abi, BUFSIZ) != 0) 809257353Sbdrewery errx(EXIT_FAILURE, "Failed to determine the system " 810257353Sbdrewery "ABI"); 811247841Sbapt c[ABI].val = abi; 812247841Sbapt } 813247841Sbapt 814247843Sbapt subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 815247841Sbapt 816247841Sbapt return (0); 817247841Sbapt} 818247841Sbapt 819247841Sbaptint 820247841Sbaptconfig_string(pkg_config_key k, const char **val) 821247841Sbapt{ 822247841Sbapt if (c[k].type != PKG_CONFIG_STRING) 823247841Sbapt return (-1); 824247841Sbapt 825247841Sbapt if (c[k].value != NULL) 826247841Sbapt *val = c[k].value; 827247841Sbapt else 828247841Sbapt *val = c[k].val; 829247841Sbapt 830247841Sbapt return (0); 831247841Sbapt} 832247841Sbapt 833247841Sbaptint 834247841Sbaptconfig_bool(pkg_config_key k, bool *val) 835247841Sbapt{ 836247841Sbapt const char *value; 837247841Sbapt 838247841Sbapt if (c[k].type != PKG_CONFIG_BOOL) 839247841Sbapt return (-1); 840247841Sbapt 841247841Sbapt *val = false; 842247841Sbapt 843247841Sbapt if (c[k].value != NULL) 844247841Sbapt value = c[k].value; 845247841Sbapt else 846247841Sbapt value = c[k].val; 847247841Sbapt 848259613Sbdrewery if (boolstr_to_bool(value)) 849247841Sbapt *val = true; 850247841Sbapt 851247841Sbapt return (0); 852247841Sbapt} 853247841Sbapt 854247841Sbaptvoid 855247841Sbaptconfig_finish(void) { 856247841Sbapt int i; 857247841Sbapt 858247841Sbapt for (i = 0; i < CONFIG_SIZE; i++) 859247841Sbapt free(c[i].value); 860247841Sbapt} 861