xref: /freebsd/usr.sbin/pkg/config.c (revision fd9ae9ac04edf9acef4a2ffbf663698a2b8e7ced)
19950eceeSBaptiste Daroussin /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
40ad5dbacSBaptiste Daroussin  * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
5f12db248SBryan Drewery  * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
69950eceeSBaptiste Daroussin  * All rights reserved.
79950eceeSBaptiste Daroussin  *
89950eceeSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
99950eceeSBaptiste Daroussin  * modification, are permitted provided that the following conditions
109950eceeSBaptiste Daroussin  * are met:
119950eceeSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
129950eceeSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
139950eceeSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
149950eceeSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in the
159950eceeSBaptiste Daroussin  *    documentation and/or other materials provided with the distribution.
169950eceeSBaptiste Daroussin  *
179950eceeSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
189950eceeSBaptiste Daroussin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
199950eceeSBaptiste Daroussin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
209950eceeSBaptiste Daroussin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
219950eceeSBaptiste Daroussin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
229950eceeSBaptiste Daroussin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
239950eceeSBaptiste Daroussin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
249950eceeSBaptiste Daroussin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
259950eceeSBaptiste Daroussin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
269950eceeSBaptiste Daroussin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
279950eceeSBaptiste Daroussin  * SUCH DAMAGE.
289950eceeSBaptiste Daroussin  */
299950eceeSBaptiste Daroussin 
309950eceeSBaptiste Daroussin #include <sys/cdefs.h>
319950eceeSBaptiste Daroussin #include <sys/param.h>
32a351c93dSBaptiste Daroussin #include <sys/queue.h>
3360b9a1fcSNathan Whitehorn #include <sys/utsname.h>
3460b9a1fcSNathan Whitehorn #include <sys/sysctl.h>
359950eceeSBaptiste Daroussin 
36eb31a574SBryan Drewery #include <dirent.h>
378a7d859eSBaptiste Daroussin #include <ucl.h>
389950eceeSBaptiste Daroussin #include <err.h>
399950eceeSBaptiste Daroussin #include <errno.h>
4056d11d4aSStefan Eßer #include <libutil.h>
411f474190SStefan Eßer #include <paths.h>
429950eceeSBaptiste Daroussin #include <stdbool.h>
439950eceeSBaptiste Daroussin #include <unistd.h>
44e869d3c6SMoritz Schmitt #include <ctype.h>
459950eceeSBaptiste Daroussin 
469950eceeSBaptiste Daroussin #include "config.h"
479950eceeSBaptiste Daroussin 
48eb31a574SBryan Drewery struct config_value {
49eb31a574SBryan Drewery 	char *value;
50eb31a574SBryan Drewery 	STAILQ_ENTRY(config_value) next;
51eb31a574SBryan Drewery };
52eb31a574SBryan Drewery 
539950eceeSBaptiste Daroussin struct config_entry {
549950eceeSBaptiste Daroussin 	uint8_t type;
559950eceeSBaptiste Daroussin 	const char *key;
569950eceeSBaptiste Daroussin 	const char *val;
579950eceeSBaptiste Daroussin 	char *value;
58eb31a574SBryan Drewery 	STAILQ_HEAD(, config_value) *list;
599950eceeSBaptiste Daroussin 	bool envset;
6097c3a766SBryan Drewery 	bool main_only;				/* Only set in pkg.conf. */
619950eceeSBaptiste Daroussin };
629950eceeSBaptiste 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 
147*fd9ae9acSJohn Baldwin static char *
148*fd9ae9acSJohn Baldwin pkg_get_myabi(void)
1499950eceeSBaptiste Daroussin {
15060b9a1fcSNathan Whitehorn 	struct utsname uts;
15160b9a1fcSNathan Whitehorn 	char machine_arch[255];
152*fd9ae9acSJohn Baldwin 	char *abi;
15360b9a1fcSNathan Whitehorn 	size_t len;
15460b9a1fcSNathan Whitehorn 	int error;
1559950eceeSBaptiste Daroussin 
15660b9a1fcSNathan Whitehorn 	error = uname(&uts);
15760b9a1fcSNathan Whitehorn 	if (error)
158*fd9ae9acSJohn 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)
163*fd9ae9acSJohn 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 	 */
170*fd9ae9acSJohn Baldwin 	error = asprintf(&abi, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000,
17160b9a1fcSNathan Whitehorn 	    machine_arch);
172*fd9ae9acSJohn Baldwin 	if (error < 0)
173*fd9ae9acSJohn Baldwin 		return (NULL);
17440274a2dSBaptiste Daroussin 
175*fd9ae9acSJohn 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
215b04a7a0bSBaptiste Daroussin config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
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 
242bc5e9ac0SBryan Drewery 		if (conftype == CONFFILE_PKG) {
2438a7d859eSBaptiste Daroussin 			for (j = 0; j < strlen(key); ++j)
244cc9a8a11SBaptiste Daroussin 				fputc(toupper(key[j]), buffp);
245cc9a8a11SBaptiste Daroussin 			fflush(buffp);
246bc5e9ac0SBryan Drewery 		} else if (conftype == CONFFILE_REPO) {
2478a7d859eSBaptiste Daroussin 			if (strcasecmp(key, "url") == 0)
248cc9a8a11SBaptiste Daroussin 				fputs("PACKAGESITE", buffp);
2498a7d859eSBaptiste Daroussin 			else if (strcasecmp(key, "mirror_type") == 0)
250cc9a8a11SBaptiste Daroussin 				fputs("MIRROR_TYPE", buffp);
2518a7d859eSBaptiste Daroussin 			else if (strcasecmp(key, "signature_type") == 0)
252cc9a8a11SBaptiste Daroussin 				fputs("SIGNATURE_TYPE", buffp);
2538a7d859eSBaptiste Daroussin 			else if (strcasecmp(key, "fingerprints") == 0)
254cc9a8a11SBaptiste Daroussin 				fputs("FINGERPRINTS", buffp);
25561acb458SBaptiste Daroussin 			else if (strcasecmp(key, "pubkey") == 0)
256cc9a8a11SBaptiste Daroussin 				fputs("PUBKEY", buffp);
2578a7d859eSBaptiste Daroussin 			else if (strcasecmp(key, "enabled") == 0) {
2588a7d859eSBaptiste Daroussin 				if ((cur->type != UCL_BOOLEAN) ||
2598a7d859eSBaptiste Daroussin 				    !ucl_object_toboolean(cur))
260eb31a574SBryan Drewery 					goto cleanup;
2618a7d859eSBaptiste Daroussin 			} else
262bc5e9ac0SBryan Drewery 				continue;
263cc9a8a11SBaptiste Daroussin 			fflush(buffp);
264bc5e9ac0SBryan Drewery 		}
265bc5e9ac0SBryan Drewery 
2669950eceeSBaptiste Daroussin 		for (i = 0; i < CONFIG_SIZE; i++) {
267cc9a8a11SBaptiste Daroussin 			if (strcmp(buf, c[i].key) == 0)
2689950eceeSBaptiste Daroussin 				break;
2699950eceeSBaptiste Daroussin 		}
2709950eceeSBaptiste Daroussin 
271bc5e9ac0SBryan Drewery 		/* Silently skip unknown keys to be future compatible. */
2728a7d859eSBaptiste Daroussin 		if (i == CONFIG_SIZE)
2739950eceeSBaptiste Daroussin 			continue;
2749950eceeSBaptiste Daroussin 
2759950eceeSBaptiste Daroussin 		/* env has priority over config file */
2768a7d859eSBaptiste Daroussin 		if (c[i].envset)
2779950eceeSBaptiste Daroussin 			continue;
2789950eceeSBaptiste Daroussin 
279eb31a574SBryan Drewery 		/* Parse sequence value ["item1", "item2"] */
280eb31a574SBryan Drewery 		switch (c[i].type) {
281eb31a574SBryan Drewery 		case PKG_CONFIG_LIST:
2828a7d859eSBaptiste Daroussin 			if (cur->type != UCL_ARRAY) {
2838a7d859eSBaptiste Daroussin 				warnx("Skipping invalid array "
284eb31a574SBryan Drewery 				    "value for %s.\n", c[i].key);
285eb31a574SBryan Drewery 				continue;
286eb31a574SBryan Drewery 			}
287eb31a574SBryan Drewery 			temp_config[i].list =
288eb31a574SBryan Drewery 			    malloc(sizeof(*temp_config[i].list));
289eb31a574SBryan Drewery 			STAILQ_INIT(temp_config[i].list);
290eb31a574SBryan Drewery 
2918a7d859eSBaptiste Daroussin 			while ((seq = ucl_iterate_object(cur, &itseq, true))) {
2928a7d859eSBaptiste Daroussin 				if (seq->type != UCL_STRING)
293eb31a574SBryan Drewery 					continue;
294eb31a574SBryan Drewery 				cv = malloc(sizeof(struct config_value));
295eb31a574SBryan Drewery 				cv->value =
2968a7d859eSBaptiste Daroussin 				    strdup(ucl_object_tostring(seq));
297eb31a574SBryan Drewery 				STAILQ_INSERT_TAIL(temp_config[i].list, cv,
298eb31a574SBryan Drewery 				    next);
299eb31a574SBryan Drewery 			}
300eb31a574SBryan Drewery 			break;
301197372c2SBryan Drewery 		case PKG_CONFIG_BOOL:
302197372c2SBryan Drewery 			temp_config[i].value =
303197372c2SBryan Drewery 			    strdup(ucl_object_toboolean(cur) ? "yes" : "no");
304197372c2SBryan Drewery 			break;
305e869d3c6SMoritz Schmitt 		case PKG_CONFIG_OBJECT:
306e869d3c6SMoritz Schmitt 			if (strcmp(c[i].key, "PKG_ENV") == 0) {
307e869d3c6SMoritz Schmitt 				while ((tmp =
308e869d3c6SMoritz Schmitt 				    ucl_iterate_object(cur, &it_obj, true))) {
309e869d3c6SMoritz Schmitt 					evkey = ucl_object_key(tmp);
310e869d3c6SMoritz Schmitt 					if (evkey != NULL && *evkey != '\0') {
311e869d3c6SMoritz Schmitt 						setenv(evkey, ucl_object_tostring_forced(tmp), 1);
312e869d3c6SMoritz Schmitt 					}
313e869d3c6SMoritz Schmitt 				}
314e869d3c6SMoritz Schmitt 			}
315e869d3c6SMoritz Schmitt 			break;
316eb31a574SBryan Drewery 		default:
317eb31a574SBryan Drewery 			/* Normal string value. */
3188a7d859eSBaptiste Daroussin 			temp_config[i].value = strdup(ucl_object_tostring(cur));
319eb31a574SBryan Drewery 			break;
320eb31a574SBryan Drewery 		}
3219950eceeSBaptiste Daroussin 	}
3229950eceeSBaptiste Daroussin 
323eb31a574SBryan Drewery 	/* Repo is enabled, copy over all settings from temp_config. */
324eb31a574SBryan Drewery 	for (i = 0; i < CONFIG_SIZE; i++) {
325eb31a574SBryan Drewery 		if (c[i].envset)
326eb31a574SBryan Drewery 			continue;
32797c3a766SBryan Drewery 		/* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
32897c3a766SBryan Drewery 		if (conftype != CONFFILE_PKG && c[i].main_only == true)
32997c3a766SBryan Drewery 			continue;
330eb31a574SBryan Drewery 		switch (c[i].type) {
331eb31a574SBryan Drewery 		case PKG_CONFIG_LIST:
332eb31a574SBryan Drewery 			c[i].list = temp_config[i].list;
333eb31a574SBryan Drewery 			break;
334eb31a574SBryan Drewery 		default:
335eb31a574SBryan Drewery 			c[i].value = temp_config[i].value;
336eb31a574SBryan Drewery 			break;
337eb31a574SBryan Drewery 		}
338eb31a574SBryan Drewery 	}
339eb31a574SBryan Drewery 
340eb31a574SBryan Drewery cleanup:
341eb31a574SBryan Drewery 	free(temp_config);
342cc9a8a11SBaptiste Daroussin 	fclose(buffp);
343cc9a8a11SBaptiste Daroussin 	free(buf);
3449950eceeSBaptiste Daroussin }
3459950eceeSBaptiste Daroussin 
346bc5e9ac0SBryan Drewery /*-
347bc5e9ac0SBryan Drewery  * Parse new repo style configs in style:
348bc5e9ac0SBryan Drewery  * Name:
349bc5e9ac0SBryan Drewery  *   URL:
350bc5e9ac0SBryan Drewery  *   MIRROR_TYPE:
351bc5e9ac0SBryan Drewery  * etc...
352bc5e9ac0SBryan Drewery  */
353bc5e9ac0SBryan Drewery static void
35418418e19SKyle Evans parse_repo_file(ucl_object_t *obj, const char *requested_repo)
355bc5e9ac0SBryan Drewery {
3568a7d859eSBaptiste Daroussin 	ucl_object_iter_t it = NULL;
357b04a7a0bSBaptiste Daroussin 	const ucl_object_t *cur;
3588a7d859eSBaptiste Daroussin 	const char *key;
359bc5e9ac0SBryan Drewery 
3608a7d859eSBaptiste Daroussin 	while ((cur = ucl_iterate_object(obj, &it, true))) {
3618a7d859eSBaptiste Daroussin 		key = ucl_object_key(cur);
362bc5e9ac0SBryan Drewery 
3638a7d859eSBaptiste Daroussin 		if (key == NULL)
364bc5e9ac0SBryan Drewery 			continue;
365bc5e9ac0SBryan Drewery 
3668a7d859eSBaptiste Daroussin 		if (cur->type != UCL_OBJECT)
367bc5e9ac0SBryan Drewery 			continue;
368bc5e9ac0SBryan Drewery 
36918418e19SKyle Evans 		if (requested_repo != NULL && strcmp(requested_repo, key) != 0)
37018418e19SKyle Evans 			continue;
37118418e19SKyle Evans 
3728a7d859eSBaptiste Daroussin 		config_parse(cur, CONFFILE_REPO);
373bc5e9ac0SBryan Drewery 	}
374bc5e9ac0SBryan Drewery }
375bc5e9ac0SBryan Drewery 
376bc5e9ac0SBryan Drewery 
377bc5e9ac0SBryan Drewery static int
37818418e19SKyle Evans read_conf_file(const char *confpath, const char *requested_repo,
37918418e19SKyle Evans     pkg_conf_file_t conftype)
3809950eceeSBaptiste Daroussin {
3818a7d859eSBaptiste Daroussin 	struct ucl_parser *p;
3828a7d859eSBaptiste Daroussin 	ucl_object_t *obj = NULL;
383bc5e9ac0SBryan Drewery 
3848a7d859eSBaptiste Daroussin 	p = ucl_parser_new(0);
3858a7d859eSBaptiste Daroussin 
3868a7d859eSBaptiste Daroussin 	if (!ucl_parser_add_file(p, confpath)) {
387bc5e9ac0SBryan Drewery 		if (errno != ENOENT)
3888a7d859eSBaptiste Daroussin 			errx(EXIT_FAILURE, "Unable to parse configuration "
3898a7d859eSBaptiste Daroussin 			    "file %s: %s", confpath, ucl_parser_get_error(p));
3908a7d859eSBaptiste Daroussin 		ucl_parser_free(p);
391bc5e9ac0SBryan Drewery 		/* no configuration present */
392bc5e9ac0SBryan Drewery 		return (1);
393bc5e9ac0SBryan Drewery 	}
394bc5e9ac0SBryan Drewery 
3958a7d859eSBaptiste Daroussin 	obj = ucl_parser_get_object(p);
3968a7d859eSBaptiste Daroussin 	if (obj->type != UCL_OBJECT)
397bc5e9ac0SBryan Drewery 		warnx("Invalid configuration format, ignoring the "
398bc5e9ac0SBryan Drewery 		    "configuration file %s", confpath);
399bc5e9ac0SBryan Drewery 	else {
400bc5e9ac0SBryan Drewery 		if (conftype == CONFFILE_PKG)
4018a7d859eSBaptiste Daroussin 			config_parse(obj, conftype);
402bc5e9ac0SBryan Drewery 		else if (conftype == CONFFILE_REPO)
40318418e19SKyle Evans 			parse_repo_file(obj, requested_repo);
404bc5e9ac0SBryan Drewery 	}
405bc5e9ac0SBryan Drewery 
406b04a7a0bSBaptiste Daroussin 	ucl_object_unref(obj);
4078a7d859eSBaptiste Daroussin 	ucl_parser_free(p);
408bc5e9ac0SBryan Drewery 
409bc5e9ac0SBryan Drewery 	return (0);
410bc5e9ac0SBryan Drewery }
411bc5e9ac0SBryan Drewery 
412eb31a574SBryan Drewery static int
41318418e19SKyle Evans load_repositories(const char *repodir, const char *requested_repo)
414eb31a574SBryan Drewery {
415eb31a574SBryan Drewery 	struct dirent *ent;
416eb31a574SBryan Drewery 	DIR *d;
417eb31a574SBryan Drewery 	char *p;
418eb31a574SBryan Drewery 	size_t n;
419eb31a574SBryan Drewery 	char path[MAXPATHLEN];
420eb31a574SBryan Drewery 	int ret;
421eb31a574SBryan Drewery 
422eb31a574SBryan Drewery 	ret = 0;
423eb31a574SBryan Drewery 
424eb31a574SBryan Drewery 	if ((d = opendir(repodir)) == NULL)
425eb31a574SBryan Drewery 		return (1);
426eb31a574SBryan Drewery 
427eb31a574SBryan Drewery 	while ((ent = readdir(d))) {
428eb31a574SBryan Drewery 		/* Trim out 'repos'. */
429eb31a574SBryan Drewery 		if ((n = strlen(ent->d_name)) <= 5)
430eb31a574SBryan Drewery 			continue;
431eb31a574SBryan Drewery 		p = &ent->d_name[n - 5];
432eb31a574SBryan Drewery 		if (strcmp(p, ".conf") == 0) {
433eb31a574SBryan Drewery 			snprintf(path, sizeof(path), "%s%s%s",
434eb31a574SBryan Drewery 			    repodir,
435eb31a574SBryan Drewery 			    repodir[strlen(repodir) - 1] == '/' ? "" : "/",
436eb31a574SBryan Drewery 			    ent->d_name);
43718418e19SKyle Evans 			if (access(path, F_OK) != 0)
43818418e19SKyle Evans 				continue;
43918418e19SKyle Evans 			if (read_conf_file(path, requested_repo,
44018418e19SKyle Evans 			    CONFFILE_REPO)) {
441eb31a574SBryan Drewery 				ret = 1;
442eb31a574SBryan Drewery 				goto cleanup;
443eb31a574SBryan Drewery 			}
444eb31a574SBryan Drewery 		}
445eb31a574SBryan Drewery 	}
446eb31a574SBryan Drewery 
447eb31a574SBryan Drewery cleanup:
448eb31a574SBryan Drewery 	closedir(d);
449eb31a574SBryan Drewery 
450eb31a574SBryan Drewery 	return (ret);
451eb31a574SBryan Drewery }
452eb31a574SBryan Drewery 
453bc5e9ac0SBryan Drewery int
45418418e19SKyle Evans config_init(const char *requested_repo)
455bc5e9ac0SBryan Drewery {
456eb31a574SBryan Drewery 	char *val;
4579950eceeSBaptiste Daroussin 	int i;
4589950eceeSBaptiste Daroussin 	const char *localbase;
459*fd9ae9acSJohn Baldwin 	char *abi, *env_list_item;
4609950eceeSBaptiste Daroussin 	char confpath[MAXPATHLEN];
461eb31a574SBryan Drewery 	struct config_value *cv;
4629950eceeSBaptiste Daroussin 
4639950eceeSBaptiste Daroussin 	for (i = 0; i < CONFIG_SIZE; i++) {
4649950eceeSBaptiste Daroussin 		val = getenv(c[i].key);
4659950eceeSBaptiste Daroussin 		if (val != NULL) {
4669950eceeSBaptiste Daroussin 			c[i].envset = true;
467eb31a574SBryan Drewery 			switch (c[i].type) {
468eb31a574SBryan Drewery 			case PKG_CONFIG_LIST:
469eb31a574SBryan Drewery 				/* Split up comma-separated items from env. */
470eb31a574SBryan Drewery 				c[i].list = malloc(sizeof(*c[i].list));
471eb31a574SBryan Drewery 				STAILQ_INIT(c[i].list);
472eb31a574SBryan Drewery 				for (env_list_item = strtok(val, ",");
473eb31a574SBryan Drewery 				    env_list_item != NULL;
474eb31a574SBryan Drewery 				    env_list_item = strtok(NULL, ",")) {
475eb31a574SBryan Drewery 					cv =
476eb31a574SBryan Drewery 					    malloc(sizeof(struct config_value));
477eb31a574SBryan Drewery 					cv->value =
478eb31a574SBryan Drewery 					    strdup(env_list_item);
479eb31a574SBryan Drewery 					STAILQ_INSERT_TAIL(c[i].list, cv,
480eb31a574SBryan Drewery 					    next);
481eb31a574SBryan Drewery 				}
482eb31a574SBryan Drewery 				break;
483eb31a574SBryan Drewery 			default:
484eb31a574SBryan Drewery 				c[i].val = val;
485eb31a574SBryan Drewery 				break;
486eb31a574SBryan Drewery 			}
4879950eceeSBaptiste Daroussin 		}
4889950eceeSBaptiste Daroussin 	}
4899950eceeSBaptiste Daroussin 
490eb31a574SBryan Drewery 	/* Read LOCALBASE/etc/pkg.conf first. */
49156d11d4aSStefan Eßer 	localbase = getlocalbase();
49256d11d4aSStefan Eßer 	snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf", localbase);
4939950eceeSBaptiste Daroussin 
49418418e19SKyle Evans 	if (access(confpath, F_OK) == 0 && read_conf_file(confpath, NULL,
495bc5e9ac0SBryan Drewery 	    CONFFILE_PKG))
4969950eceeSBaptiste Daroussin 		goto finalize;
4979950eceeSBaptiste Daroussin 
498eb31a574SBryan Drewery 	/* Then read in all repos from REPOS_DIR list of directories. */
499eb31a574SBryan Drewery 	if (c[REPOS_DIR].list == NULL) {
500eb31a574SBryan Drewery 		c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
501eb31a574SBryan Drewery 		STAILQ_INIT(c[REPOS_DIR].list);
502eb31a574SBryan Drewery 		cv = malloc(sizeof(struct config_value));
503eb31a574SBryan Drewery 		cv->value = strdup("/etc/pkg");
504eb31a574SBryan Drewery 		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
505eb31a574SBryan Drewery 		cv = malloc(sizeof(struct config_value));
506eb31a574SBryan Drewery 		if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
507eb31a574SBryan Drewery 			goto finalize;
508eb31a574SBryan Drewery 		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
509eb31a574SBryan Drewery 	}
510eb31a574SBryan Drewery 
511eb31a574SBryan Drewery 	STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
51218418e19SKyle Evans 		if (load_repositories(cv->value, requested_repo))
513bc5e9ac0SBryan Drewery 			goto finalize;
5149950eceeSBaptiste Daroussin 
5159950eceeSBaptiste Daroussin finalize:
5169950eceeSBaptiste Daroussin 	if (c[ABI].val == NULL && c[ABI].value == NULL) {
517*fd9ae9acSJohn Baldwin 		abi = pkg_get_myabi();
518*fd9ae9acSJohn Baldwin 		if (abi == NULL)
5194ff9a7efSBryan Drewery 			errx(EXIT_FAILURE, "Failed to determine the system "
5204ff9a7efSBryan Drewery 			    "ABI");
5219950eceeSBaptiste Daroussin 		c[ABI].val = abi;
5229950eceeSBaptiste Daroussin 	}
5239950eceeSBaptiste Daroussin 
524d5bf8a8bSBaptiste Daroussin 	subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val);
5259950eceeSBaptiste Daroussin 
5269950eceeSBaptiste Daroussin 	return (0);
5279950eceeSBaptiste Daroussin }
5289950eceeSBaptiste Daroussin 
5299950eceeSBaptiste Daroussin int
5309950eceeSBaptiste Daroussin config_string(pkg_config_key k, const char **val)
5319950eceeSBaptiste Daroussin {
5329950eceeSBaptiste Daroussin 	if (c[k].type != PKG_CONFIG_STRING)
5339950eceeSBaptiste Daroussin 		return (-1);
5349950eceeSBaptiste Daroussin 
5359950eceeSBaptiste Daroussin 	if (c[k].value != NULL)
5369950eceeSBaptiste Daroussin 		*val = c[k].value;
5379950eceeSBaptiste Daroussin 	else
5389950eceeSBaptiste Daroussin 		*val = c[k].val;
5399950eceeSBaptiste Daroussin 
5409950eceeSBaptiste Daroussin 	return (0);
5419950eceeSBaptiste Daroussin }
5429950eceeSBaptiste Daroussin 
5439950eceeSBaptiste Daroussin int
5449950eceeSBaptiste Daroussin config_bool(pkg_config_key k, bool *val)
5459950eceeSBaptiste Daroussin {
5469950eceeSBaptiste Daroussin 	const char *value;
5479950eceeSBaptiste Daroussin 
5489950eceeSBaptiste Daroussin 	if (c[k].type != PKG_CONFIG_BOOL)
5499950eceeSBaptiste Daroussin 		return (-1);
5509950eceeSBaptiste Daroussin 
5519950eceeSBaptiste Daroussin 	*val = false;
5529950eceeSBaptiste Daroussin 
5539950eceeSBaptiste Daroussin 	if (c[k].value != NULL)
5549950eceeSBaptiste Daroussin 		value = c[k].value;
5559950eceeSBaptiste Daroussin 	else
5569950eceeSBaptiste Daroussin 		value = c[k].val;
5579950eceeSBaptiste Daroussin 
558eb31a574SBryan Drewery 	if (boolstr_to_bool(value))
5599950eceeSBaptiste Daroussin 		*val = true;
5609950eceeSBaptiste Daroussin 
5619950eceeSBaptiste Daroussin 	return (0);
5629950eceeSBaptiste Daroussin }
5639950eceeSBaptiste Daroussin 
5649950eceeSBaptiste Daroussin void
5659950eceeSBaptiste Daroussin config_finish(void) {
5669950eceeSBaptiste Daroussin 	int i;
5679950eceeSBaptiste Daroussin 
5689950eceeSBaptiste Daroussin 	for (i = 0; i < CONFIG_SIZE; i++)
5699950eceeSBaptiste Daroussin 		free(c[i].value);
5709950eceeSBaptiste Daroussin }
571