19950eceeSBaptiste Daroussin /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 31de7b4b8SPedro F. Giffuni * 4eccf736cSBaptiste Daroussin * Copyright (c) 2014-2025 Baptiste Daroussin <bapt@FreeBSD.org> 5f12db248SBryan Drewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org> 69950eceeSBaptiste Daroussin * 79950eceeSBaptiste Daroussin * Redistribution and use in source and binary forms, with or without 89950eceeSBaptiste Daroussin * modification, are permitted provided that the following conditions 99950eceeSBaptiste Daroussin * are met: 109950eceeSBaptiste Daroussin * 1. Redistributions of source code must retain the above copyright 119950eceeSBaptiste Daroussin * notice, this list of conditions and the following disclaimer. 129950eceeSBaptiste Daroussin * 2. Redistributions in binary form must reproduce the above copyright 139950eceeSBaptiste Daroussin * notice, this list of conditions and the following disclaimer in the 149950eceeSBaptiste Daroussin * documentation and/or other materials provided with the distribution. 159950eceeSBaptiste Daroussin * 169950eceeSBaptiste Daroussin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 179950eceeSBaptiste Daroussin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 189950eceeSBaptiste Daroussin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 199950eceeSBaptiste Daroussin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 209950eceeSBaptiste Daroussin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 219950eceeSBaptiste Daroussin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 229950eceeSBaptiste Daroussin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 239950eceeSBaptiste Daroussin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 249950eceeSBaptiste Daroussin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 259950eceeSBaptiste Daroussin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 269950eceeSBaptiste Daroussin * SUCH DAMAGE. 279950eceeSBaptiste Daroussin */ 289950eceeSBaptiste Daroussin 299950eceeSBaptiste Daroussin #include <sys/param.h> 30a351c93dSBaptiste Daroussin #include <sys/queue.h> 3160b9a1fcSNathan Whitehorn #include <sys/utsname.h> 3260b9a1fcSNathan Whitehorn #include <sys/sysctl.h> 339950eceeSBaptiste Daroussin 34eb31a574SBryan Drewery #include <dirent.h> 358a7d859eSBaptiste Daroussin #include <ucl.h> 369950eceeSBaptiste Daroussin #include <err.h> 379950eceeSBaptiste Daroussin #include <errno.h> 3856d11d4aSStefan Eßer #include <libutil.h> 391f474190SStefan Eßer #include <paths.h> 409950eceeSBaptiste Daroussin #include <stdbool.h> 419950eceeSBaptiste Daroussin #include <unistd.h> 42e869d3c6SMoritz Schmitt #include <ctype.h> 439950eceeSBaptiste Daroussin 449950eceeSBaptiste Daroussin #include "config.h" 459950eceeSBaptiste Daroussin 46eb31a574SBryan Drewery struct config_value { 47eb31a574SBryan Drewery char *value; 48eb31a574SBryan Drewery STAILQ_ENTRY(config_value) next; 49eb31a574SBryan Drewery }; 50eb31a574SBryan Drewery 519950eceeSBaptiste Daroussin struct config_entry { 529950eceeSBaptiste Daroussin uint8_t type; 539950eceeSBaptiste Daroussin const char *key; 549950eceeSBaptiste Daroussin const char *val; 559950eceeSBaptiste Daroussin char *value; 56eb31a574SBryan Drewery STAILQ_HEAD(, config_value) *list; 579950eceeSBaptiste Daroussin bool envset; 5897c3a766SBryan Drewery bool main_only; /* Only set in pkg.conf. */ 599950eceeSBaptiste Daroussin }; 609950eceeSBaptiste Daroussin 61dc458158SBaptiste Daroussin static struct repositories repositories = STAILQ_HEAD_INITIALIZER(repositories); 62dc458158SBaptiste Daroussin 639950eceeSBaptiste Daroussin static struct config_entry c[] = { 649950eceeSBaptiste Daroussin [PACKAGESITE] = { 659950eceeSBaptiste Daroussin PKG_CONFIG_STRING, 669950eceeSBaptiste Daroussin "PACKAGESITE", 6762940ea9SBryan Drewery URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest", 689950eceeSBaptiste Daroussin NULL, 69eb31a574SBryan Drewery NULL, 709950eceeSBaptiste Daroussin false, 7197c3a766SBryan Drewery false, 729950eceeSBaptiste Daroussin }, 739950eceeSBaptiste Daroussin [ABI] = { 749950eceeSBaptiste Daroussin PKG_CONFIG_STRING, 759950eceeSBaptiste Daroussin "ABI", 769950eceeSBaptiste Daroussin NULL, 779950eceeSBaptiste Daroussin NULL, 78eb31a574SBryan Drewery NULL, 799950eceeSBaptiste Daroussin false, 8097c3a766SBryan Drewery true, 819950eceeSBaptiste Daroussin }, 829950eceeSBaptiste Daroussin [MIRROR_TYPE] = { 839950eceeSBaptiste Daroussin PKG_CONFIG_STRING, 849950eceeSBaptiste Daroussin "MIRROR_TYPE", 859950eceeSBaptiste Daroussin "SRV", 869950eceeSBaptiste Daroussin NULL, 87eb31a574SBryan Drewery NULL, 889950eceeSBaptiste Daroussin false, 8997c3a766SBryan Drewery false, 909950eceeSBaptiste Daroussin }, 919950eceeSBaptiste Daroussin [ASSUME_ALWAYS_YES] = { 929950eceeSBaptiste Daroussin PKG_CONFIG_BOOL, 939950eceeSBaptiste Daroussin "ASSUME_ALWAYS_YES", 949950eceeSBaptiste Daroussin "NO", 959950eceeSBaptiste Daroussin NULL, 96eb31a574SBryan Drewery NULL, 979950eceeSBaptiste Daroussin false, 9897c3a766SBryan Drewery true, 99f12db248SBryan Drewery }, 100f12db248SBryan Drewery [SIGNATURE_TYPE] = { 101f12db248SBryan Drewery PKG_CONFIG_STRING, 102f12db248SBryan Drewery "SIGNATURE_TYPE", 103f12db248SBryan Drewery NULL, 104f12db248SBryan Drewery NULL, 105eb31a574SBryan Drewery NULL, 106f12db248SBryan Drewery false, 10797c3a766SBryan Drewery false, 108f12db248SBryan Drewery }, 109f12db248SBryan Drewery [FINGERPRINTS] = { 110f12db248SBryan Drewery PKG_CONFIG_STRING, 111f12db248SBryan Drewery "FINGERPRINTS", 112f12db248SBryan Drewery NULL, 113f12db248SBryan Drewery NULL, 114eb31a574SBryan Drewery NULL, 115eb31a574SBryan Drewery false, 11697c3a766SBryan Drewery false, 117eb31a574SBryan Drewery }, 118eb31a574SBryan Drewery [REPOS_DIR] = { 119eb31a574SBryan Drewery PKG_CONFIG_LIST, 120eb31a574SBryan Drewery "REPOS_DIR", 121eb31a574SBryan Drewery NULL, 122eb31a574SBryan Drewery NULL, 123eb31a574SBryan Drewery NULL, 124f12db248SBryan Drewery false, 12597c3a766SBryan Drewery true, 126f12db248SBryan Drewery }, 12761acb458SBaptiste Daroussin [PUBKEY] = { 12861acb458SBaptiste Daroussin PKG_CONFIG_STRING, 12961acb458SBaptiste Daroussin "PUBKEY", 13061acb458SBaptiste Daroussin NULL, 13161acb458SBaptiste Daroussin NULL, 13261acb458SBaptiste Daroussin NULL, 13361acb458SBaptiste Daroussin false, 13461acb458SBaptiste Daroussin false 135e869d3c6SMoritz Schmitt }, 136e869d3c6SMoritz Schmitt [PKG_ENV] = { 137e869d3c6SMoritz Schmitt PKG_CONFIG_OBJECT, 138e869d3c6SMoritz Schmitt "PKG_ENV", 139e869d3c6SMoritz Schmitt NULL, 140e869d3c6SMoritz Schmitt NULL, 141e869d3c6SMoritz Schmitt NULL, 142e869d3c6SMoritz Schmitt false, 143e869d3c6SMoritz Schmitt false, 14461acb458SBaptiste Daroussin } 1459950eceeSBaptiste Daroussin }; 1469950eceeSBaptiste Daroussin 147fd9ae9acSJohn Baldwin static char * 148fd9ae9acSJohn Baldwin pkg_get_myabi(void) 1499950eceeSBaptiste Daroussin { 15060b9a1fcSNathan Whitehorn struct utsname uts; 15160b9a1fcSNathan Whitehorn char machine_arch[255]; 152fd9ae9acSJohn Baldwin char *abi; 15360b9a1fcSNathan Whitehorn size_t len; 15460b9a1fcSNathan Whitehorn int error; 1559950eceeSBaptiste Daroussin 15660b9a1fcSNathan Whitehorn error = uname(&uts); 15760b9a1fcSNathan Whitehorn if (error) 158fd9ae9acSJohn Baldwin return (NULL); 1599950eceeSBaptiste Daroussin 16060b9a1fcSNathan Whitehorn len = sizeof(machine_arch); 16160b9a1fcSNathan Whitehorn error = sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0); 16260b9a1fcSNathan Whitehorn if (error) 163fd9ae9acSJohn Baldwin return (NULL); 16460b9a1fcSNathan Whitehorn machine_arch[len] = '\0'; 1659950eceeSBaptiste Daroussin 16640274a2dSBaptiste Daroussin /* 16760b9a1fcSNathan Whitehorn * Use __FreeBSD_version rather than kernel version (uts.release) for 16860b9a1fcSNathan Whitehorn * use in jails. This is equivalent to the value of uname -U. 16940274a2dSBaptiste Daroussin */ 170fd9ae9acSJohn Baldwin error = asprintf(&abi, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000, 17160b9a1fcSNathan Whitehorn machine_arch); 172fd9ae9acSJohn Baldwin if (error < 0) 173fd9ae9acSJohn Baldwin return (NULL); 17440274a2dSBaptiste Daroussin 175fd9ae9acSJohn Baldwin return (abi); 1769950eceeSBaptiste Daroussin } 1779950eceeSBaptiste Daroussin 1789950eceeSBaptiste Daroussin static void 1799950eceeSBaptiste Daroussin subst_packagesite(const char *abi) 1809950eceeSBaptiste Daroussin { 181ae659caaSBaptiste Daroussin char *newval; 1829950eceeSBaptiste Daroussin const char *variable_string; 1839950eceeSBaptiste Daroussin const char *oldval; 1849950eceeSBaptiste Daroussin 1859950eceeSBaptiste Daroussin if (c[PACKAGESITE].value != NULL) 1869950eceeSBaptiste Daroussin oldval = c[PACKAGESITE].value; 1879950eceeSBaptiste Daroussin else 1889950eceeSBaptiste Daroussin oldval = c[PACKAGESITE].val; 1899950eceeSBaptiste Daroussin 1909950eceeSBaptiste Daroussin if ((variable_string = strstr(oldval, "${ABI}")) == NULL) 1919950eceeSBaptiste Daroussin return; 1929950eceeSBaptiste Daroussin 193ae659caaSBaptiste Daroussin asprintf(&newval, "%.*s%s%s", 194ae659caaSBaptiste Daroussin (int)(variable_string - oldval), oldval, abi, 195ae659caaSBaptiste Daroussin variable_string + strlen("${ABI}")); 196ae659caaSBaptiste Daroussin if (newval == NULL) 197ae659caaSBaptiste Daroussin errx(EXIT_FAILURE, "asprintf"); 1989950eceeSBaptiste Daroussin 1999950eceeSBaptiste Daroussin free(c[PACKAGESITE].value); 200ae659caaSBaptiste Daroussin c[PACKAGESITE].value = newval; 2019950eceeSBaptiste Daroussin } 2029950eceeSBaptiste Daroussin 203eb31a574SBryan Drewery static int 204eb31a574SBryan Drewery boolstr_to_bool(const char *str) 205eb31a574SBryan Drewery { 206eb31a574SBryan Drewery if (str != NULL && (strcasecmp(str, "true") == 0 || 207eb31a574SBryan Drewery strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 || 208eb31a574SBryan Drewery str[0] == '1')) 209eb31a574SBryan Drewery return (true); 210eb31a574SBryan Drewery 211eb31a574SBryan Drewery return (false); 212eb31a574SBryan Drewery } 213eb31a574SBryan Drewery 2149950eceeSBaptiste Daroussin static void 215dc458158SBaptiste Daroussin config_parse(const ucl_object_t *obj) 2169950eceeSBaptiste Daroussin { 217cc9a8a11SBaptiste Daroussin FILE *buffp; 218cc9a8a11SBaptiste Daroussin char *buf = NULL; 219cc9a8a11SBaptiste Daroussin size_t bufsz = 0; 220e869d3c6SMoritz Schmitt const ucl_object_t *cur, *seq, *tmp; 221e869d3c6SMoritz Schmitt ucl_object_iter_t it = NULL, itseq = NULL, it_obj = NULL; 222eb31a574SBryan Drewery struct config_entry *temp_config; 223eb31a574SBryan Drewery struct config_value *cv; 224e869d3c6SMoritz Schmitt const char *key, *evkey; 2259950eceeSBaptiste Daroussin int i; 2269950eceeSBaptiste Daroussin size_t j; 2279950eceeSBaptiste Daroussin 228eb31a574SBryan Drewery /* Temporary config for configs that may be disabled. */ 229eb31a574SBryan Drewery temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry)); 230cc9a8a11SBaptiste Daroussin buffp = open_memstream(&buf, &bufsz); 231cc9a8a11SBaptiste Daroussin if (buffp == NULL) 232cc9a8a11SBaptiste Daroussin err(EXIT_FAILURE, "open_memstream()"); 233eb31a574SBryan Drewery 2348a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 2358a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 2368a7d859eSBaptiste Daroussin if (key == NULL) 2379950eceeSBaptiste Daroussin continue; 238cc9a8a11SBaptiste Daroussin if (buf != NULL) 239cc9a8a11SBaptiste Daroussin memset(buf, 0, bufsz); 240cc9a8a11SBaptiste Daroussin rewind(buffp); 2419950eceeSBaptiste Daroussin 2428a7d859eSBaptiste Daroussin for (j = 0; j < strlen(key); ++j) 243cc9a8a11SBaptiste Daroussin fputc(toupper(key[j]), buffp); 244cc9a8a11SBaptiste Daroussin fflush(buffp); 245bc5e9ac0SBryan Drewery 2469950eceeSBaptiste Daroussin for (i = 0; i < CONFIG_SIZE; i++) { 247cc9a8a11SBaptiste Daroussin if (strcmp(buf, c[i].key) == 0) 2489950eceeSBaptiste Daroussin break; 2499950eceeSBaptiste Daroussin } 2509950eceeSBaptiste Daroussin 251bc5e9ac0SBryan Drewery /* Silently skip unknown keys to be future compatible. */ 2528a7d859eSBaptiste Daroussin if (i == CONFIG_SIZE) 2539950eceeSBaptiste Daroussin continue; 2549950eceeSBaptiste Daroussin 2559950eceeSBaptiste Daroussin /* env has priority over config file */ 2568a7d859eSBaptiste Daroussin if (c[i].envset) 2579950eceeSBaptiste Daroussin continue; 2589950eceeSBaptiste Daroussin 259eb31a574SBryan Drewery /* Parse sequence value ["item1", "item2"] */ 260eb31a574SBryan Drewery switch (c[i].type) { 261eb31a574SBryan Drewery case PKG_CONFIG_LIST: 2628a7d859eSBaptiste Daroussin if (cur->type != UCL_ARRAY) { 2638a7d859eSBaptiste Daroussin warnx("Skipping invalid array " 264eb31a574SBryan Drewery "value for %s.\n", c[i].key); 265eb31a574SBryan Drewery continue; 266eb31a574SBryan Drewery } 267eb31a574SBryan Drewery temp_config[i].list = 268eb31a574SBryan Drewery malloc(sizeof(*temp_config[i].list)); 269eb31a574SBryan Drewery STAILQ_INIT(temp_config[i].list); 270eb31a574SBryan Drewery 2718a7d859eSBaptiste Daroussin while ((seq = ucl_iterate_object(cur, &itseq, true))) { 2728a7d859eSBaptiste Daroussin if (seq->type != UCL_STRING) 273eb31a574SBryan Drewery continue; 274eb31a574SBryan Drewery cv = malloc(sizeof(struct config_value)); 275eb31a574SBryan Drewery cv->value = 2768a7d859eSBaptiste Daroussin strdup(ucl_object_tostring(seq)); 277eb31a574SBryan Drewery STAILQ_INSERT_TAIL(temp_config[i].list, cv, 278eb31a574SBryan Drewery next); 279eb31a574SBryan Drewery } 280eb31a574SBryan Drewery break; 281197372c2SBryan Drewery case PKG_CONFIG_BOOL: 282197372c2SBryan Drewery temp_config[i].value = 283197372c2SBryan Drewery strdup(ucl_object_toboolean(cur) ? "yes" : "no"); 284197372c2SBryan Drewery break; 285e869d3c6SMoritz Schmitt case PKG_CONFIG_OBJECT: 286e869d3c6SMoritz Schmitt if (strcmp(c[i].key, "PKG_ENV") == 0) { 287e869d3c6SMoritz Schmitt while ((tmp = 288e869d3c6SMoritz Schmitt ucl_iterate_object(cur, &it_obj, true))) { 289e869d3c6SMoritz Schmitt evkey = ucl_object_key(tmp); 290e869d3c6SMoritz Schmitt if (evkey != NULL && *evkey != '\0') { 291e869d3c6SMoritz Schmitt setenv(evkey, ucl_object_tostring_forced(tmp), 1); 292e869d3c6SMoritz Schmitt } 293e869d3c6SMoritz Schmitt } 294e869d3c6SMoritz Schmitt } 295e869d3c6SMoritz Schmitt break; 296eb31a574SBryan Drewery default: 297eb31a574SBryan Drewery /* Normal string value. */ 2988a7d859eSBaptiste Daroussin temp_config[i].value = strdup(ucl_object_tostring(cur)); 299eb31a574SBryan Drewery break; 300eb31a574SBryan Drewery } 3019950eceeSBaptiste Daroussin } 3029950eceeSBaptiste Daroussin 303eb31a574SBryan Drewery /* Repo is enabled, copy over all settings from temp_config. */ 304eb31a574SBryan Drewery for (i = 0; i < CONFIG_SIZE; i++) { 305eb31a574SBryan Drewery if (c[i].envset) 306eb31a574SBryan Drewery continue; 30797c3a766SBryan Drewery /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */ 308dc458158SBaptiste Daroussin if (c[i].main_only == true) 30997c3a766SBryan Drewery continue; 310eb31a574SBryan Drewery switch (c[i].type) { 311eb31a574SBryan Drewery case PKG_CONFIG_LIST: 312eb31a574SBryan Drewery c[i].list = temp_config[i].list; 313eb31a574SBryan Drewery break; 314eb31a574SBryan Drewery default: 315eb31a574SBryan Drewery c[i].value = temp_config[i].value; 316eb31a574SBryan Drewery break; 317eb31a574SBryan Drewery } 318eb31a574SBryan Drewery } 319eb31a574SBryan Drewery 320eb31a574SBryan Drewery free(temp_config); 321cc9a8a11SBaptiste Daroussin fclose(buffp); 322cc9a8a11SBaptiste Daroussin free(buf); 3239950eceeSBaptiste Daroussin } 3249950eceeSBaptiste Daroussin 325dc458158SBaptiste Daroussin 326dc458158SBaptiste Daroussin static void 327dc458158SBaptiste Daroussin parse_mirror_type(struct repository *r, const char *mt) 328dc458158SBaptiste Daroussin { 329dc458158SBaptiste Daroussin if (strcasecmp(mt, "srv") == 0) 330dc458158SBaptiste Daroussin r->mirror_type = MIRROR_SRV; 331dc458158SBaptiste Daroussin r->mirror_type = MIRROR_NONE; 332dc458158SBaptiste Daroussin } 333dc458158SBaptiste Daroussin 334eccf736cSBaptiste Daroussin static void 335eccf736cSBaptiste Daroussin repo_free(struct repository *r) 336eccf736cSBaptiste Daroussin { 337eccf736cSBaptiste Daroussin free(r->name); 338eccf736cSBaptiste Daroussin free(r->url); 339eccf736cSBaptiste Daroussin free(r->fingerprints); 340eccf736cSBaptiste Daroussin free(r->pubkey); 341eccf736cSBaptiste Daroussin free(r); 342eccf736cSBaptiste Daroussin } 343eccf736cSBaptiste Daroussin 344dc458158SBaptiste Daroussin static bool 345dc458158SBaptiste Daroussin parse_signature_type(struct repository *repo, const char *st) 346dc458158SBaptiste Daroussin { 347dc458158SBaptiste Daroussin if (strcasecmp(st, "FINGERPRINTS") == 0) 348dc458158SBaptiste Daroussin repo->signature_type = SIGNATURE_FINGERPRINT; 349dc458158SBaptiste Daroussin else if (strcasecmp(st, "PUBKEY") == 0) 350dc458158SBaptiste Daroussin repo->signature_type = SIGNATURE_PUBKEY; 351dc458158SBaptiste Daroussin else if (strcasecmp(st, "NONE") == 0) 352dc458158SBaptiste Daroussin repo->signature_type = SIGNATURE_NONE; 353dc458158SBaptiste Daroussin else { 35449f4e3d2SBenedict Reuschling warnx("Signature type %s is not supported for bootstrapping," 355dc458158SBaptiste Daroussin " ignoring repository %s", st, repo->name); 3565c341fe5SBaptiste Daroussin return (false); 357dc458158SBaptiste Daroussin } 358dc458158SBaptiste Daroussin return (true); 359dc458158SBaptiste Daroussin } 360dc458158SBaptiste Daroussin 3615c341fe5SBaptiste Daroussin static struct repository * 3625c341fe5SBaptiste Daroussin find_repository(const char *name) 3635c341fe5SBaptiste Daroussin { 3645c341fe5SBaptiste Daroussin struct repository *repo; 3655c341fe5SBaptiste Daroussin STAILQ_FOREACH(repo, &repositories, next) { 3665c341fe5SBaptiste Daroussin if (strcmp(repo->name, name) == 0) 3675c341fe5SBaptiste Daroussin return (repo); 3685c341fe5SBaptiste Daroussin } 3695c341fe5SBaptiste Daroussin return (NULL); 3705c341fe5SBaptiste Daroussin } 3715c341fe5SBaptiste Daroussin 372dc458158SBaptiste Daroussin static void 373dc458158SBaptiste Daroussin parse_repo(const ucl_object_t *o) 374dc458158SBaptiste Daroussin { 375dc458158SBaptiste Daroussin const ucl_object_t *cur; 3765c341fe5SBaptiste Daroussin const char *key, *reponame; 377dc458158SBaptiste Daroussin ucl_object_iter_t it = NULL; 3785c341fe5SBaptiste Daroussin bool newrepo = false; 3795c341fe5SBaptiste Daroussin struct repository *repo; 380dc458158SBaptiste Daroussin 3815c341fe5SBaptiste Daroussin reponame = ucl_object_key(o); 3825c341fe5SBaptiste Daroussin repo = find_repository(reponame); 3835c341fe5SBaptiste Daroussin if (repo == NULL) { 3845c341fe5SBaptiste Daroussin repo = calloc(1, sizeof(struct repository)); 385dc458158SBaptiste Daroussin if (repo == NULL) 386dc458158SBaptiste Daroussin err(EXIT_FAILURE, "calloc"); 387dc458158SBaptiste Daroussin 3885c341fe5SBaptiste Daroussin repo->name = strdup(reponame); 389dc458158SBaptiste Daroussin if (repo->name == NULL) 390dc458158SBaptiste Daroussin err(EXIT_FAILURE, "strdup"); 3915c341fe5SBaptiste Daroussin newrepo = true; 3925c341fe5SBaptiste Daroussin } 393dc458158SBaptiste Daroussin while ((cur = ucl_iterate_object(o, &it, true))) { 394dc458158SBaptiste Daroussin key = ucl_object_key(cur); 395dc458158SBaptiste Daroussin if (key == NULL) 396dc458158SBaptiste Daroussin continue; 397dc458158SBaptiste Daroussin if (strcasecmp(key, "url") == 0) { 3985c341fe5SBaptiste Daroussin free(repo->url); 399dc458158SBaptiste Daroussin repo->url = strdup(ucl_object_tostring(cur)); 400dc458158SBaptiste Daroussin if (repo->url == NULL) 401dc458158SBaptiste Daroussin err(EXIT_FAILURE, "strdup"); 402dc458158SBaptiste Daroussin } else if (strcasecmp(key, "mirror_type") == 0) { 403dc458158SBaptiste Daroussin parse_mirror_type(repo, ucl_object_tostring(cur)); 404dc458158SBaptiste Daroussin } else if (strcasecmp(key, "signature_type") == 0) { 4055c341fe5SBaptiste Daroussin if (!parse_signature_type(repo, ucl_object_tostring(cur))) { 4065c341fe5SBaptiste Daroussin if (newrepo) 4075c341fe5SBaptiste Daroussin repo_free(repo); 4085c341fe5SBaptiste Daroussin else 4095c341fe5SBaptiste Daroussin STAILQ_REMOVE(&repositories, repo, repository, next); 410dc458158SBaptiste Daroussin return; 4115c341fe5SBaptiste Daroussin } 412dc458158SBaptiste Daroussin } else if (strcasecmp(key, "fingerprints") == 0) { 4135c341fe5SBaptiste Daroussin free(repo->fingerprints); 414dc458158SBaptiste Daroussin repo->fingerprints = strdup(ucl_object_tostring(cur)); 415dc458158SBaptiste Daroussin if (repo->fingerprints == NULL) 416dc458158SBaptiste Daroussin err(EXIT_FAILURE, "strdup"); 417dc458158SBaptiste Daroussin } else if (strcasecmp(key, "pubkey") == 0) { 4185c341fe5SBaptiste Daroussin free(repo->pubkey); 419dc458158SBaptiste Daroussin repo->pubkey = strdup(ucl_object_tostring(cur)); 420dc458158SBaptiste Daroussin if (repo->pubkey == NULL) 421dc458158SBaptiste Daroussin err(EXIT_FAILURE, "strdup"); 422dc458158SBaptiste Daroussin } else if (strcasecmp(key, "enabled") == 0) { 423dc458158SBaptiste Daroussin if ((cur->type != UCL_BOOLEAN) || 424dc458158SBaptiste Daroussin !ucl_object_toboolean(cur)) { 4255c341fe5SBaptiste Daroussin if (newrepo) 426eccf736cSBaptiste Daroussin repo_free(repo); 4275c341fe5SBaptiste Daroussin else 4285c341fe5SBaptiste Daroussin STAILQ_REMOVE(&repositories, repo, repository, next); 429dc458158SBaptiste Daroussin return; 430dc458158SBaptiste Daroussin } 431dc458158SBaptiste Daroussin } 432dc458158SBaptiste Daroussin } 433eccf736cSBaptiste Daroussin /* At least we need an url */ 434eccf736cSBaptiste Daroussin if (repo->url == NULL) { 435eccf736cSBaptiste Daroussin repo_free(repo); 436eccf736cSBaptiste Daroussin return; 437eccf736cSBaptiste Daroussin } 4385c341fe5SBaptiste Daroussin if (newrepo) 439dc458158SBaptiste Daroussin STAILQ_INSERT_TAIL(&repositories, repo, next); 440dc458158SBaptiste Daroussin return; 441dc458158SBaptiste Daroussin } 442dc458158SBaptiste Daroussin 443bc5e9ac0SBryan Drewery /*- 444bc5e9ac0SBryan Drewery * Parse new repo style configs in style: 445bc5e9ac0SBryan Drewery * Name: 446bc5e9ac0SBryan Drewery * URL: 447bc5e9ac0SBryan Drewery * MIRROR_TYPE: 448bc5e9ac0SBryan Drewery * etc... 449bc5e9ac0SBryan Drewery */ 450bc5e9ac0SBryan Drewery static void 45118418e19SKyle Evans parse_repo_file(ucl_object_t *obj, const char *requested_repo) 452bc5e9ac0SBryan Drewery { 4538a7d859eSBaptiste Daroussin ucl_object_iter_t it = NULL; 454b04a7a0bSBaptiste Daroussin const ucl_object_t *cur; 4558a7d859eSBaptiste Daroussin const char *key; 456bc5e9ac0SBryan Drewery 4578a7d859eSBaptiste Daroussin while ((cur = ucl_iterate_object(obj, &it, true))) { 4588a7d859eSBaptiste Daroussin key = ucl_object_key(cur); 459bc5e9ac0SBryan Drewery 4608a7d859eSBaptiste Daroussin if (key == NULL) 461bc5e9ac0SBryan Drewery continue; 462bc5e9ac0SBryan Drewery 4638a7d859eSBaptiste Daroussin if (cur->type != UCL_OBJECT) 464bc5e9ac0SBryan Drewery continue; 465bc5e9ac0SBryan Drewery 46618418e19SKyle Evans if (requested_repo != NULL && strcmp(requested_repo, key) != 0) 46718418e19SKyle Evans continue; 468dc458158SBaptiste Daroussin parse_repo(cur); 469bc5e9ac0SBryan Drewery } 470bc5e9ac0SBryan Drewery } 471bc5e9ac0SBryan Drewery 472bc5e9ac0SBryan Drewery 473bc5e9ac0SBryan Drewery static int 47418418e19SKyle Evans read_conf_file(const char *confpath, const char *requested_repo, 47518418e19SKyle Evans pkg_conf_file_t conftype) 4769950eceeSBaptiste Daroussin { 4778a7d859eSBaptiste Daroussin struct ucl_parser *p; 4788a7d859eSBaptiste Daroussin ucl_object_t *obj = NULL; 479*c1557708SMark Johnston char *abi = pkg_get_myabi(), *major, *minor; 480e3b4a515SBaptiste Daroussin struct utsname uts; 481*c1557708SMark Johnston int ret; 482e3b4a515SBaptiste Daroussin 483e3b4a515SBaptiste Daroussin if (uname(&uts)) 484e3b4a515SBaptiste Daroussin err(EXIT_FAILURE, "uname"); 485dc458158SBaptiste Daroussin if (abi == NULL) 48649f4e3d2SBenedict Reuschling errx(EXIT_FAILURE, "Failed to determine ABI"); 487bc5e9ac0SBryan Drewery 4888a7d859eSBaptiste Daroussin p = ucl_parser_new(0); 489e3b4a515SBaptiste Daroussin asprintf(&major, "%d", __FreeBSD_version/100000); 490e3b4a515SBaptiste Daroussin if (major == NULL) 491e3b4a515SBaptiste Daroussin err(EXIT_FAILURE, "asprintf"); 492e3b4a515SBaptiste Daroussin asprintf(&minor, "%d", (__FreeBSD_version / 1000) % 100); 493e3b4a515SBaptiste Daroussin if (minor == NULL) 494e3b4a515SBaptiste Daroussin err(EXIT_FAILURE, "asprintf"); 495dc458158SBaptiste Daroussin ucl_parser_register_variable(p, "ABI", abi); 496e3b4a515SBaptiste Daroussin ucl_parser_register_variable(p, "OSNAME", uts.sysname); 497e3b4a515SBaptiste Daroussin ucl_parser_register_variable(p, "RELEASE", major); 498e3b4a515SBaptiste Daroussin ucl_parser_register_variable(p, "VERSION_MAJOR", major); 499e3b4a515SBaptiste Daroussin ucl_parser_register_variable(p, "VERSION_MINOR", minor); 5008a7d859eSBaptiste Daroussin 5018a7d859eSBaptiste Daroussin if (!ucl_parser_add_file(p, confpath)) { 502bc5e9ac0SBryan Drewery if (errno != ENOENT) 5038a7d859eSBaptiste Daroussin errx(EXIT_FAILURE, "Unable to parse configuration " 5048a7d859eSBaptiste Daroussin "file %s: %s", confpath, ucl_parser_get_error(p)); 505bc5e9ac0SBryan Drewery /* no configuration present */ 506*c1557708SMark Johnston ret = 1; 507*c1557708SMark Johnston goto out; 508bc5e9ac0SBryan Drewery } 509bc5e9ac0SBryan Drewery 5108a7d859eSBaptiste Daroussin obj = ucl_parser_get_object(p); 5118a7d859eSBaptiste Daroussin if (obj->type != UCL_OBJECT) 512bc5e9ac0SBryan Drewery warnx("Invalid configuration format, ignoring the " 513bc5e9ac0SBryan Drewery "configuration file %s", confpath); 514bc5e9ac0SBryan Drewery else { 515bc5e9ac0SBryan Drewery if (conftype == CONFFILE_PKG) 516dc458158SBaptiste Daroussin config_parse(obj); 517bc5e9ac0SBryan Drewery else if (conftype == CONFFILE_REPO) 51818418e19SKyle Evans parse_repo_file(obj, requested_repo); 519bc5e9ac0SBryan Drewery } 520b04a7a0bSBaptiste Daroussin ucl_object_unref(obj); 521*c1557708SMark Johnston 522*c1557708SMark Johnston ret = 0; 523*c1557708SMark Johnston out: 5248a7d859eSBaptiste Daroussin ucl_parser_free(p); 525*c1557708SMark Johnston free(abi); 526e3b4a515SBaptiste Daroussin free(major); 527e3b4a515SBaptiste Daroussin free(minor); 528bc5e9ac0SBryan Drewery 529*c1557708SMark Johnston return (ret); 530bc5e9ac0SBryan Drewery } 531bc5e9ac0SBryan Drewery 532dc458158SBaptiste Daroussin static void 53318418e19SKyle Evans load_repositories(const char *repodir, const char *requested_repo) 534eb31a574SBryan Drewery { 535eb31a574SBryan Drewery struct dirent *ent; 536eb31a574SBryan Drewery DIR *d; 537eb31a574SBryan Drewery char *p; 538eb31a574SBryan Drewery size_t n; 539eb31a574SBryan Drewery char path[MAXPATHLEN]; 540eb31a574SBryan Drewery 541eb31a574SBryan Drewery if ((d = opendir(repodir)) == NULL) 542dc458158SBaptiste Daroussin return; 543eb31a574SBryan Drewery 544eb31a574SBryan Drewery while ((ent = readdir(d))) { 545eb31a574SBryan Drewery /* Trim out 'repos'. */ 546eb31a574SBryan Drewery if ((n = strlen(ent->d_name)) <= 5) 547eb31a574SBryan Drewery continue; 548eb31a574SBryan Drewery p = &ent->d_name[n - 5]; 549eb31a574SBryan Drewery if (strcmp(p, ".conf") == 0) { 550eb31a574SBryan Drewery snprintf(path, sizeof(path), "%s%s%s", 551eb31a574SBryan Drewery repodir, 552eb31a574SBryan Drewery repodir[strlen(repodir) - 1] == '/' ? "" : "/", 553eb31a574SBryan Drewery ent->d_name); 55418418e19SKyle Evans if (access(path, F_OK) != 0) 55518418e19SKyle Evans continue; 55618418e19SKyle Evans if (read_conf_file(path, requested_repo, 55718418e19SKyle Evans CONFFILE_REPO)) { 558eb31a574SBryan Drewery goto cleanup; 559eb31a574SBryan Drewery } 560eb31a574SBryan Drewery } 561eb31a574SBryan Drewery } 562eb31a574SBryan Drewery 563eb31a574SBryan Drewery cleanup: 564eb31a574SBryan Drewery closedir(d); 565eb31a574SBryan Drewery } 566eb31a574SBryan Drewery 567bc5e9ac0SBryan Drewery int 56818418e19SKyle Evans config_init(const char *requested_repo) 569bc5e9ac0SBryan Drewery { 570eb31a574SBryan Drewery char *val; 5719950eceeSBaptiste Daroussin int i; 5729950eceeSBaptiste Daroussin const char *localbase; 573fd9ae9acSJohn Baldwin char *abi, *env_list_item; 5749950eceeSBaptiste Daroussin char confpath[MAXPATHLEN]; 575eb31a574SBryan Drewery struct config_value *cv; 5769950eceeSBaptiste Daroussin 5779950eceeSBaptiste Daroussin for (i = 0; i < CONFIG_SIZE; i++) { 5789950eceeSBaptiste Daroussin val = getenv(c[i].key); 5799950eceeSBaptiste Daroussin if (val != NULL) { 5809950eceeSBaptiste Daroussin c[i].envset = true; 581eb31a574SBryan Drewery switch (c[i].type) { 582eb31a574SBryan Drewery case PKG_CONFIG_LIST: 583eb31a574SBryan Drewery /* Split up comma-separated items from env. */ 584eb31a574SBryan Drewery c[i].list = malloc(sizeof(*c[i].list)); 585eb31a574SBryan Drewery STAILQ_INIT(c[i].list); 586eb31a574SBryan Drewery for (env_list_item = strtok(val, ","); 587eb31a574SBryan Drewery env_list_item != NULL; 588eb31a574SBryan Drewery env_list_item = strtok(NULL, ",")) { 589eb31a574SBryan Drewery cv = 590eb31a574SBryan Drewery malloc(sizeof(struct config_value)); 591eb31a574SBryan Drewery cv->value = 592eb31a574SBryan Drewery strdup(env_list_item); 593eb31a574SBryan Drewery STAILQ_INSERT_TAIL(c[i].list, cv, 594eb31a574SBryan Drewery next); 595eb31a574SBryan Drewery } 596eb31a574SBryan Drewery break; 597eb31a574SBryan Drewery default: 598eb31a574SBryan Drewery c[i].val = val; 599eb31a574SBryan Drewery break; 600eb31a574SBryan Drewery } 6019950eceeSBaptiste Daroussin } 6029950eceeSBaptiste Daroussin } 6039950eceeSBaptiste Daroussin 604eb31a574SBryan Drewery /* Read LOCALBASE/etc/pkg.conf first. */ 60556d11d4aSStefan Eßer localbase = getlocalbase(); 60656d11d4aSStefan Eßer snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", localbase); 6079950eceeSBaptiste Daroussin 60818418e19SKyle Evans if (access(confpath, F_OK) == 0 && read_conf_file(confpath, NULL, 609bc5e9ac0SBryan Drewery CONFFILE_PKG)) 6109950eceeSBaptiste Daroussin goto finalize; 6119950eceeSBaptiste Daroussin 612eb31a574SBryan Drewery /* Then read in all repos from REPOS_DIR list of directories. */ 613eb31a574SBryan Drewery if (c[REPOS_DIR].list == NULL) { 614eb31a574SBryan Drewery c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list)); 615eb31a574SBryan Drewery STAILQ_INIT(c[REPOS_DIR].list); 616eb31a574SBryan Drewery cv = malloc(sizeof(struct config_value)); 617eb31a574SBryan Drewery cv->value = strdup("/etc/pkg"); 618eb31a574SBryan Drewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 619eb31a574SBryan Drewery cv = malloc(sizeof(struct config_value)); 620eb31a574SBryan Drewery if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0) 621eb31a574SBryan Drewery goto finalize; 622eb31a574SBryan Drewery STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next); 623eb31a574SBryan Drewery } 624eb31a574SBryan Drewery 625eb31a574SBryan Drewery STAILQ_FOREACH(cv, c[REPOS_DIR].list, next) 626dc458158SBaptiste Daroussin load_repositories(cv->value, requested_repo); 6279950eceeSBaptiste Daroussin 6289950eceeSBaptiste Daroussin finalize: 6299950eceeSBaptiste Daroussin if (c[ABI].val == NULL && c[ABI].value == NULL) { 630fd9ae9acSJohn Baldwin abi = pkg_get_myabi(); 631fd9ae9acSJohn Baldwin if (abi == NULL) 6324ff9a7efSBryan Drewery errx(EXIT_FAILURE, "Failed to determine the system " 6334ff9a7efSBryan Drewery "ABI"); 6349950eceeSBaptiste Daroussin c[ABI].val = abi; 6359950eceeSBaptiste Daroussin } 6369950eceeSBaptiste Daroussin 6379950eceeSBaptiste Daroussin return (0); 6389950eceeSBaptiste Daroussin } 6399950eceeSBaptiste Daroussin 6409950eceeSBaptiste Daroussin int 6419950eceeSBaptiste Daroussin config_string(pkg_config_key k, const char **val) 6429950eceeSBaptiste Daroussin { 6439950eceeSBaptiste Daroussin if (c[k].type != PKG_CONFIG_STRING) 6449950eceeSBaptiste Daroussin return (-1); 6459950eceeSBaptiste Daroussin 6469950eceeSBaptiste Daroussin if (c[k].value != NULL) 6479950eceeSBaptiste Daroussin *val = c[k].value; 6489950eceeSBaptiste Daroussin else 6499950eceeSBaptiste Daroussin *val = c[k].val; 6509950eceeSBaptiste Daroussin 6519950eceeSBaptiste Daroussin return (0); 6529950eceeSBaptiste Daroussin } 6539950eceeSBaptiste Daroussin 6549950eceeSBaptiste Daroussin int 6559950eceeSBaptiste Daroussin config_bool(pkg_config_key k, bool *val) 6569950eceeSBaptiste Daroussin { 6579950eceeSBaptiste Daroussin const char *value; 6589950eceeSBaptiste Daroussin 6599950eceeSBaptiste Daroussin if (c[k].type != PKG_CONFIG_BOOL) 6609950eceeSBaptiste Daroussin return (-1); 6619950eceeSBaptiste Daroussin 6629950eceeSBaptiste Daroussin *val = false; 6639950eceeSBaptiste Daroussin 6649950eceeSBaptiste Daroussin if (c[k].value != NULL) 6659950eceeSBaptiste Daroussin value = c[k].value; 6669950eceeSBaptiste Daroussin else 6679950eceeSBaptiste Daroussin value = c[k].val; 6689950eceeSBaptiste Daroussin 669eb31a574SBryan Drewery if (boolstr_to_bool(value)) 6709950eceeSBaptiste Daroussin *val = true; 6719950eceeSBaptiste Daroussin 6729950eceeSBaptiste Daroussin return (0); 6739950eceeSBaptiste Daroussin } 6749950eceeSBaptiste Daroussin 675dc458158SBaptiste Daroussin struct repositories * 676dc458158SBaptiste Daroussin config_get_repositories(void) 677dc458158SBaptiste Daroussin { 678dc458158SBaptiste Daroussin if (STAILQ_EMPTY(&repositories)) { 679dc458158SBaptiste Daroussin /* Fall back to PACKAGESITE - deprecated - */ 680*c1557708SMark Johnston struct repository *r = calloc(1, sizeof(*r)); 681dc458158SBaptiste Daroussin if (r == NULL) 682dc458158SBaptiste Daroussin err(EXIT_FAILURE, "calloc"); 683dc458158SBaptiste Daroussin r->name = strdup("fallback"); 684dc458158SBaptiste Daroussin if (r->name == NULL) 685dc458158SBaptiste Daroussin err(EXIT_FAILURE, "strdup"); 686dc458158SBaptiste Daroussin subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val); 687dc458158SBaptiste Daroussin r->url = c[PACKAGESITE].value; 688dc458158SBaptiste Daroussin if (c[SIGNATURE_TYPE].value != NULL) 689dc458158SBaptiste Daroussin if (!parse_signature_type(r, c[SIGNATURE_TYPE].value)) 690dc458158SBaptiste Daroussin exit(EXIT_FAILURE); 691dc458158SBaptiste Daroussin if (c[MIRROR_TYPE].value != NULL) 692dc458158SBaptiste Daroussin parse_mirror_type(r, c[MIRROR_TYPE].value); 693dc458158SBaptiste Daroussin if (c[PUBKEY].value != NULL) 694dc458158SBaptiste Daroussin r->pubkey = c[PUBKEY].value; 695dc458158SBaptiste Daroussin if (c[FINGERPRINTS].value != NULL) 696dc458158SBaptiste Daroussin r->fingerprints = c[FINGERPRINTS].value; 697dc458158SBaptiste Daroussin STAILQ_INSERT_TAIL(&repositories, r, next); 698dc458158SBaptiste Daroussin } 699dc458158SBaptiste Daroussin return (&repositories); 700dc458158SBaptiste Daroussin } 701dc458158SBaptiste Daroussin 7029950eceeSBaptiste Daroussin void 7039950eceeSBaptiste Daroussin config_finish(void) { 7049950eceeSBaptiste Daroussin int i; 7059950eceeSBaptiste Daroussin 7069950eceeSBaptiste Daroussin for (i = 0; i < CONFIG_SIZE; i++) 7079950eceeSBaptiste Daroussin free(c[i].value); 7089950eceeSBaptiste Daroussin } 709