1247841Sbapt/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
4262401Sbapt * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
5257147Sbdrewery * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
6247841Sbapt * All rights reserved.
7247841Sbapt *
8247841Sbapt * Redistribution and use in source and binary forms, with or without
9247841Sbapt * modification, are permitted provided that the following conditions
10247841Sbapt * are met:
11247841Sbapt * 1. Redistributions of source code must retain the above copyright
12247841Sbapt *    notice, this list of conditions and the following disclaimer.
13247841Sbapt * 2. Redistributions in binary form must reproduce the above copyright
14247841Sbapt *    notice, this list of conditions and the following disclaimer in the
15247841Sbapt *    documentation and/or other materials provided with the distribution.
16247841Sbapt *
17247841Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18247841Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19247841Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20247841Sbapt * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21247841Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22247841Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23247841Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24247841Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25247841Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26247841Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27247841Sbapt * SUCH DAMAGE.
28247841Sbapt */
29247841Sbapt
30247841Sbapt#include <sys/cdefs.h>
31247841Sbapt__FBSDID("$FreeBSD: stable/11/usr.sbin/pkg/config.c 330449 2018-03-05 07:26:05Z eadler $");
32247841Sbapt
33247841Sbapt#include <sys/param.h>
34260942Sbapt#include <sys/queue.h>
35247841Sbapt#include <sys/sbuf.h>
36273754Snwhitehorn#include <sys/utsname.h>
37273754Snwhitehorn#include <sys/sysctl.h>
38247841Sbapt
39259266Sbdrewery#include <dirent.h>
40262400Sbapt#include <ucl.h>
41247841Sbapt#include <err.h>
42247841Sbapt#include <errno.h>
43247841Sbapt#include <stdbool.h>
44247841Sbapt#include <unistd.h>
45247841Sbapt
46247841Sbapt#include "config.h"
47247841Sbapt
48247841Sbapt#define roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
49247841Sbapt
50259266Sbdrewerystruct config_value {
51259266Sbdrewery       char *value;
52259266Sbdrewery       STAILQ_ENTRY(config_value) next;
53259266Sbdrewery};
54259266Sbdrewery
55247841Sbaptstruct config_entry {
56247841Sbapt	uint8_t type;
57247841Sbapt	const char *key;
58247841Sbapt	const char *val;
59247841Sbapt	char *value;
60259266Sbdrewery	STAILQ_HEAD(, config_value) *list;
61247841Sbapt	bool envset;
62263180Sbdrewery	bool main_only;				/* Only set in pkg.conf. */
63247841Sbapt};
64247841Sbapt
65247841Sbaptstatic struct config_entry c[] = {
66247841Sbapt	[PACKAGESITE] = {
67247841Sbapt		PKG_CONFIG_STRING,
68247841Sbapt		"PACKAGESITE",
69257051Sbdrewery		URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest",
70247841Sbapt		NULL,
71259266Sbdrewery		NULL,
72247841Sbapt		false,
73263180Sbdrewery		false,
74247841Sbapt	},
75247841Sbapt	[ABI] = {
76247841Sbapt		PKG_CONFIG_STRING,
77247841Sbapt		"ABI",
78247841Sbapt		NULL,
79247841Sbapt		NULL,
80259266Sbdrewery		NULL,
81247841Sbapt		false,
82263180Sbdrewery		true,
83247841Sbapt	},
84247841Sbapt	[MIRROR_TYPE] = {
85247841Sbapt		PKG_CONFIG_STRING,
86247841Sbapt		"MIRROR_TYPE",
87247841Sbapt		"SRV",
88247841Sbapt		NULL,
89259266Sbdrewery		NULL,
90247841Sbapt		false,
91263180Sbdrewery		false,
92247841Sbapt	},
93247841Sbapt	[ASSUME_ALWAYS_YES] = {
94247841Sbapt		PKG_CONFIG_BOOL,
95247841Sbapt		"ASSUME_ALWAYS_YES",
96247841Sbapt		"NO",
97247841Sbapt		NULL,
98259266Sbdrewery		NULL,
99247841Sbapt		false,
100263180Sbdrewery		true,
101257147Sbdrewery	},
102257147Sbdrewery	[SIGNATURE_TYPE] = {
103257147Sbdrewery		PKG_CONFIG_STRING,
104257147Sbdrewery		"SIGNATURE_TYPE",
105257147Sbdrewery		NULL,
106257147Sbdrewery		NULL,
107259266Sbdrewery		NULL,
108257147Sbdrewery		false,
109263180Sbdrewery		false,
110257147Sbdrewery	},
111257147Sbdrewery	[FINGERPRINTS] = {
112257147Sbdrewery		PKG_CONFIG_STRING,
113257147Sbdrewery		"FINGERPRINTS",
114257147Sbdrewery		NULL,
115257147Sbdrewery		NULL,
116259266Sbdrewery		NULL,
117257147Sbdrewery		false,
118263180Sbdrewery		false,
119257147Sbdrewery	},
120259266Sbdrewery	[REPOS_DIR] = {
121259266Sbdrewery		PKG_CONFIG_LIST,
122259266Sbdrewery		"REPOS_DIR",
123259266Sbdrewery		NULL,
124259266Sbdrewery		NULL,
125259266Sbdrewery		NULL,
126259266Sbdrewery		false,
127263180Sbdrewery		true,
128259266Sbdrewery	},
129287579Sbapt	[PUBKEY] = {
130287579Sbapt		PKG_CONFIG_STRING,
131287579Sbapt		"PUBKEY",
132287579Sbapt		NULL,
133287579Sbapt		NULL,
134287579Sbapt		NULL,
135287579Sbapt		false,
136287579Sbapt		false
137287579Sbapt	}
138247841Sbapt};
139247841Sbapt
140273754Snwhitehornstatic int
141273754Snwhitehornpkg_get_myabi(char *dest, size_t sz)
142247841Sbapt{
143273754Snwhitehorn	struct utsname uts;
144273754Snwhitehorn	char machine_arch[255];
145273754Snwhitehorn	size_t len;
146273754Snwhitehorn	int error;
147247841Sbapt
148273754Snwhitehorn	error = uname(&uts);
149273754Snwhitehorn	if (error)
150273754Snwhitehorn		return (errno);
151247841Sbapt
152273754Snwhitehorn	len = sizeof(machine_arch);
153273754Snwhitehorn	error = sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0);
154273754Snwhitehorn	if (error)
155273754Snwhitehorn		return (errno);
156273754Snwhitehorn	machine_arch[len] = '\0';
157247841Sbapt
158255457Sbapt	/*
159273754Snwhitehorn	 * Use __FreeBSD_version rather than kernel version (uts.release) for
160273754Snwhitehorn	 * use in jails. This is equivalent to the value of uname -U.
161255457Sbapt	 */
162273754Snwhitehorn	snprintf(dest, sz, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000,
163273754Snwhitehorn	    machine_arch);
164255457Sbapt
165273754Snwhitehorn	return (error);
166255457Sbapt}
167255457Sbapt
168247841Sbaptstatic void
169247841Sbaptsubst_packagesite(const char *abi)
170247841Sbapt{
171247841Sbapt	struct sbuf *newval;
172247841Sbapt	const char *variable_string;
173247841Sbapt	const char *oldval;
174247841Sbapt
175247841Sbapt	if (c[PACKAGESITE].value != NULL)
176247841Sbapt		oldval = c[PACKAGESITE].value;
177247841Sbapt	else
178247841Sbapt		oldval = c[PACKAGESITE].val;
179247841Sbapt
180247841Sbapt	if ((variable_string = strstr(oldval, "${ABI}")) == NULL)
181247841Sbapt		return;
182247841Sbapt
183247841Sbapt	newval = sbuf_new_auto();
184247841Sbapt	sbuf_bcat(newval, oldval, variable_string - oldval);
185247841Sbapt	sbuf_cat(newval, abi);
186247841Sbapt	sbuf_cat(newval, variable_string + strlen("${ABI}"));
187247841Sbapt	sbuf_finish(newval);
188247841Sbapt
189247841Sbapt	free(c[PACKAGESITE].value);
190247841Sbapt	c[PACKAGESITE].value = strdup(sbuf_data(newval));
191247841Sbapt}
192247841Sbapt
193259266Sbdrewerystatic int
194259266Sbdreweryboolstr_to_bool(const char *str)
195259266Sbdrewery{
196259266Sbdrewery	if (str != NULL && (strcasecmp(str, "true") == 0 ||
197259266Sbdrewery	    strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
198259266Sbdrewery	    str[0] == '1'))
199259266Sbdrewery		return (true);
200259266Sbdrewery
201259266Sbdrewery	return (false);
202259266Sbdrewery}
203259266Sbdrewery
204247841Sbaptstatic void
205264789Sbaptconfig_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
206247841Sbapt{
207247841Sbapt	struct sbuf *buf = sbuf_new_auto();
208264789Sbapt	const ucl_object_t *cur, *seq;
209262400Sbapt	ucl_object_iter_t it = NULL, itseq = NULL;
210259266Sbdrewery	struct config_entry *temp_config;
211259266Sbdrewery	struct config_value *cv;
212262400Sbapt	const char *key;
213247841Sbapt	int i;
214247841Sbapt	size_t j;
215247841Sbapt
216259266Sbdrewery	/* Temporary config for configs that may be disabled. */
217259266Sbdrewery	temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry));
218259266Sbdrewery
219262400Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
220262400Sbapt		key = ucl_object_key(cur);
221262400Sbapt		if (key == NULL)
222247841Sbapt			continue;
223247841Sbapt		sbuf_clear(buf);
224247841Sbapt
225257145Sbdrewery		if (conftype == CONFFILE_PKG) {
226262400Sbapt			for (j = 0; j < strlen(key); ++j)
227262400Sbapt				sbuf_putc(buf, key[j]);
228257145Sbdrewery			sbuf_finish(buf);
229257145Sbdrewery		} else if (conftype == CONFFILE_REPO) {
230262400Sbapt			if (strcasecmp(key, "url") == 0)
231257145Sbdrewery				sbuf_cpy(buf, "PACKAGESITE");
232262400Sbapt			else if (strcasecmp(key, "mirror_type") == 0)
233257145Sbdrewery				sbuf_cpy(buf, "MIRROR_TYPE");
234262400Sbapt			else if (strcasecmp(key, "signature_type") == 0)
235257147Sbdrewery				sbuf_cpy(buf, "SIGNATURE_TYPE");
236262400Sbapt			else if (strcasecmp(key, "fingerprints") == 0)
237257147Sbdrewery				sbuf_cpy(buf, "FINGERPRINTS");
238287579Sbapt			else if (strcasecmp(key, "pubkey") == 0)
239287579Sbapt				sbuf_cpy(buf, "PUBKEY");
240262400Sbapt			else if (strcasecmp(key, "enabled") == 0) {
241262400Sbapt				if ((cur->type != UCL_BOOLEAN) ||
242262400Sbapt				    !ucl_object_toboolean(cur))
243259266Sbdrewery					goto cleanup;
244262400Sbapt			} else
245257145Sbdrewery				continue;
246257145Sbdrewery			sbuf_finish(buf);
247257145Sbdrewery		}
248257145Sbdrewery
249247841Sbapt		for (i = 0; i < CONFIG_SIZE; i++) {
250247841Sbapt			if (strcmp(sbuf_data(buf), c[i].key) == 0)
251247841Sbapt				break;
252247841Sbapt		}
253247841Sbapt
254257145Sbdrewery		/* Silently skip unknown keys to be future compatible. */
255262400Sbapt		if (i == CONFIG_SIZE)
256247841Sbapt			continue;
257247841Sbapt
258247841Sbapt		/* env has priority over config file */
259262400Sbapt		if (c[i].envset)
260247841Sbapt			continue;
261247841Sbapt
262259266Sbdrewery		/* Parse sequence value ["item1", "item2"] */
263259266Sbdrewery		switch (c[i].type) {
264259266Sbdrewery		case PKG_CONFIG_LIST:
265262400Sbapt			if (cur->type != UCL_ARRAY) {
266262400Sbapt				warnx("Skipping invalid array "
267259266Sbdrewery				    "value for %s.\n", c[i].key);
268259266Sbdrewery				continue;
269259266Sbdrewery			}
270259266Sbdrewery			temp_config[i].list =
271259266Sbdrewery			    malloc(sizeof(*temp_config[i].list));
272259266Sbdrewery			STAILQ_INIT(temp_config[i].list);
273259266Sbdrewery
274262400Sbapt			while ((seq = ucl_iterate_object(cur, &itseq, true))) {
275262400Sbapt				if (seq->type != UCL_STRING)
276259266Sbdrewery					continue;
277259266Sbdrewery				cv = malloc(sizeof(struct config_value));
278259266Sbdrewery				cv->value =
279262400Sbapt				    strdup(ucl_object_tostring(seq));
280259266Sbdrewery				STAILQ_INSERT_TAIL(temp_config[i].list, cv,
281259266Sbdrewery				    next);
282259266Sbdrewery			}
283259266Sbdrewery			break;
284263181Sbdrewery		case PKG_CONFIG_BOOL:
285263181Sbdrewery			temp_config[i].value =
286263181Sbdrewery			    strdup(ucl_object_toboolean(cur) ? "yes" : "no");
287263181Sbdrewery			break;
288259266Sbdrewery		default:
289259266Sbdrewery			/* Normal string value. */
290262400Sbapt			temp_config[i].value = strdup(ucl_object_tostring(cur));
291259266Sbdrewery			break;
292259266Sbdrewery		}
293247841Sbapt	}
294247841Sbapt
295259266Sbdrewery	/* Repo is enabled, copy over all settings from temp_config. */
296259266Sbdrewery	for (i = 0; i < CONFIG_SIZE; i++) {
297259266Sbdrewery		if (c[i].envset)
298259266Sbdrewery			continue;
299263180Sbdrewery		/* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
300263180Sbdrewery		if (conftype != CONFFILE_PKG && c[i].main_only == true)
301263180Sbdrewery			continue;
302259266Sbdrewery		switch (c[i].type) {
303259266Sbdrewery		case PKG_CONFIG_LIST:
304259266Sbdrewery			c[i].list = temp_config[i].list;
305259266Sbdrewery			break;
306259266Sbdrewery		default:
307259266Sbdrewery			c[i].value = temp_config[i].value;
308259266Sbdrewery			break;
309259266Sbdrewery		}
310259266Sbdrewery	}
311259266Sbdrewery
312259266Sbdrewerycleanup:
313259266Sbdrewery	free(temp_config);
314247841Sbapt	sbuf_delete(buf);
315247841Sbapt}
316247841Sbapt
317257145Sbdrewery/*-
318257145Sbdrewery * Parse new repo style configs in style:
319257145Sbdrewery * Name:
320257145Sbdrewery *   URL:
321257145Sbdrewery *   MIRROR_TYPE:
322257145Sbdrewery * etc...
323257145Sbdrewery */
324257145Sbdrewerystatic void
325262400Sbaptparse_repo_file(ucl_object_t *obj)
326247841Sbapt{
327262400Sbapt	ucl_object_iter_t it = NULL;
328264789Sbapt	const ucl_object_t *cur;
329262400Sbapt	const char *key;
330257145Sbdrewery
331262400Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
332262400Sbapt		key = ucl_object_key(cur);
333257145Sbdrewery
334262400Sbapt		if (key == NULL)
335257145Sbdrewery			continue;
336257145Sbdrewery
337262400Sbapt		if (cur->type != UCL_OBJECT)
338257145Sbdrewery			continue;
339257145Sbdrewery
340262400Sbapt		config_parse(cur, CONFFILE_REPO);
341257145Sbdrewery	}
342257145Sbdrewery}
343257145Sbdrewery
344257145Sbdrewery
345257145Sbdrewerystatic int
346257145Sbdreweryread_conf_file(const char *confpath, pkg_conf_file_t conftype)
347257145Sbdrewery{
348262400Sbapt	struct ucl_parser *p;
349262400Sbapt	ucl_object_t *obj = NULL;
350247841Sbapt
351262400Sbapt	p = ucl_parser_new(0);
352262400Sbapt
353262400Sbapt	if (!ucl_parser_add_file(p, confpath)) {
354247841Sbapt		if (errno != ENOENT)
355262400Sbapt			errx(EXIT_FAILURE, "Unable to parse configuration "
356262400Sbapt			    "file %s: %s", confpath, ucl_parser_get_error(p));
357262400Sbapt		ucl_parser_free(p);
358247841Sbapt		/* no configuration present */
359257145Sbdrewery		return (1);
360247841Sbapt	}
361247841Sbapt
362262400Sbapt	obj = ucl_parser_get_object(p);
363262400Sbapt	if (obj->type != UCL_OBJECT)
364257142Sbdrewery		warnx("Invalid configuration format, ignoring the "
365257145Sbdrewery		    "configuration file %s", confpath);
366257145Sbdrewery	else {
367257145Sbdrewery		if (conftype == CONFFILE_PKG)
368262400Sbapt			config_parse(obj, conftype);
369257145Sbdrewery		else if (conftype == CONFFILE_REPO)
370262400Sbapt			parse_repo_file(obj);
371247841Sbapt	}
372247841Sbapt
373264789Sbapt	ucl_object_unref(obj);
374262400Sbapt	ucl_parser_free(p);
375247841Sbapt
376257145Sbdrewery	return (0);
377257145Sbdrewery}
378257145Sbdrewery
379259266Sbdrewerystatic int
380259266Sbdreweryload_repositories(const char *repodir)
381259266Sbdrewery{
382259266Sbdrewery	struct dirent *ent;
383259266Sbdrewery	DIR *d;
384259266Sbdrewery	char *p;
385259266Sbdrewery	size_t n;
386259266Sbdrewery	char path[MAXPATHLEN];
387259266Sbdrewery	int ret;
388259266Sbdrewery
389259266Sbdrewery	ret = 0;
390259266Sbdrewery
391259266Sbdrewery	if ((d = opendir(repodir)) == NULL)
392259266Sbdrewery		return (1);
393259266Sbdrewery
394259266Sbdrewery	while ((ent = readdir(d))) {
395259266Sbdrewery		/* Trim out 'repos'. */
396259266Sbdrewery		if ((n = strlen(ent->d_name)) <= 5)
397259266Sbdrewery			continue;
398259266Sbdrewery		p = &ent->d_name[n - 5];
399259266Sbdrewery		if (strcmp(p, ".conf") == 0) {
400259266Sbdrewery			snprintf(path, sizeof(path), "%s%s%s",
401259266Sbdrewery			    repodir,
402259266Sbdrewery			    repodir[strlen(repodir) - 1] == '/' ? "" : "/",
403259266Sbdrewery			    ent->d_name);
404259266Sbdrewery			if (access(path, F_OK) == 0 &&
405259266Sbdrewery			    read_conf_file(path, CONFFILE_REPO)) {
406259266Sbdrewery				ret = 1;
407259266Sbdrewery				goto cleanup;
408259266Sbdrewery			}
409259266Sbdrewery		}
410259266Sbdrewery	}
411259266Sbdrewery
412259266Sbdrewerycleanup:
413259266Sbdrewery	closedir(d);
414259266Sbdrewery
415259266Sbdrewery	return (ret);
416259266Sbdrewery}
417259266Sbdrewery
418257145Sbdreweryint
419257145Sbdreweryconfig_init(void)
420257145Sbdrewery{
421259266Sbdrewery	char *val;
422257145Sbdrewery	int i;
423257145Sbdrewery	const char *localbase;
424259266Sbdrewery	char *env_list_item;
425257145Sbdrewery	char confpath[MAXPATHLEN];
426259266Sbdrewery	struct config_value *cv;
427257145Sbdrewery	char abi[BUFSIZ];
428257145Sbdrewery
429257145Sbdrewery	for (i = 0; i < CONFIG_SIZE; i++) {
430257145Sbdrewery		val = getenv(c[i].key);
431257145Sbdrewery		if (val != NULL) {
432257145Sbdrewery			c[i].envset = true;
433259266Sbdrewery			switch (c[i].type) {
434259266Sbdrewery			case PKG_CONFIG_LIST:
435259266Sbdrewery				/* Split up comma-separated items from env. */
436259266Sbdrewery				c[i].list = malloc(sizeof(*c[i].list));
437259266Sbdrewery				STAILQ_INIT(c[i].list);
438259266Sbdrewery				for (env_list_item = strtok(val, ",");
439259266Sbdrewery				    env_list_item != NULL;
440259266Sbdrewery				    env_list_item = strtok(NULL, ",")) {
441259266Sbdrewery					cv =
442259266Sbdrewery					    malloc(sizeof(struct config_value));
443259266Sbdrewery					cv->value =
444259266Sbdrewery					    strdup(env_list_item);
445259266Sbdrewery					STAILQ_INSERT_TAIL(c[i].list, cv,
446259266Sbdrewery					    next);
447259266Sbdrewery				}
448259266Sbdrewery				break;
449259266Sbdrewery			default:
450259266Sbdrewery				c[i].val = val;
451259266Sbdrewery				break;
452259266Sbdrewery			}
453257145Sbdrewery		}
454257145Sbdrewery	}
455257145Sbdrewery
456259266Sbdrewery	/* Read LOCALBASE/etc/pkg.conf first. */
457257145Sbdrewery	localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE;
458257145Sbdrewery	snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf",
459257145Sbdrewery	    localbase);
460257145Sbdrewery
461257145Sbdrewery	if (access(confpath, F_OK) == 0 && read_conf_file(confpath,
462257145Sbdrewery	    CONFFILE_PKG))
463257145Sbdrewery		goto finalize;
464257145Sbdrewery
465259266Sbdrewery	/* Then read in all repos from REPOS_DIR list of directories. */
466259266Sbdrewery	if (c[REPOS_DIR].list == NULL) {
467259266Sbdrewery		c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
468259266Sbdrewery		STAILQ_INIT(c[REPOS_DIR].list);
469259266Sbdrewery		cv = malloc(sizeof(struct config_value));
470259266Sbdrewery		cv->value = strdup("/etc/pkg");
471259266Sbdrewery		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
472259266Sbdrewery		cv = malloc(sizeof(struct config_value));
473259266Sbdrewery		if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
474259266Sbdrewery			goto finalize;
475259266Sbdrewery		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
476259266Sbdrewery	}
477257145Sbdrewery
478259266Sbdrewery	STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
479259266Sbdrewery		if (load_repositories(cv->value))
480259266Sbdrewery			goto finalize;
481259266Sbdrewery
482247841Sbaptfinalize:
483247841Sbapt	if (c[ABI].val == NULL && c[ABI].value == NULL) {
484247841Sbapt		if (pkg_get_myabi(abi, BUFSIZ) != 0)
485257142Sbdrewery			errx(EXIT_FAILURE, "Failed to determine the system "
486257142Sbdrewery			    "ABI");
487247841Sbapt		c[ABI].val = abi;
488247841Sbapt	}
489247841Sbapt
490247843Sbapt	subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val);
491247841Sbapt
492247841Sbapt	return (0);
493247841Sbapt}
494247841Sbapt
495247841Sbaptint
496247841Sbaptconfig_string(pkg_config_key k, const char **val)
497247841Sbapt{
498247841Sbapt	if (c[k].type != PKG_CONFIG_STRING)
499247841Sbapt		return (-1);
500247841Sbapt
501247841Sbapt	if (c[k].value != NULL)
502247841Sbapt		*val = c[k].value;
503247841Sbapt	else
504247841Sbapt		*val = c[k].val;
505247841Sbapt
506247841Sbapt	return (0);
507247841Sbapt}
508247841Sbapt
509247841Sbaptint
510247841Sbaptconfig_bool(pkg_config_key k, bool *val)
511247841Sbapt{
512247841Sbapt	const char *value;
513247841Sbapt
514247841Sbapt	if (c[k].type != PKG_CONFIG_BOOL)
515247841Sbapt		return (-1);
516247841Sbapt
517247841Sbapt	*val = false;
518247841Sbapt
519247841Sbapt	if (c[k].value != NULL)
520247841Sbapt		value = c[k].value;
521247841Sbapt	else
522247841Sbapt		value = c[k].val;
523247841Sbapt
524259266Sbdrewery	if (boolstr_to_bool(value))
525247841Sbapt		*val = true;
526247841Sbapt
527247841Sbapt	return (0);
528247841Sbapt}
529247841Sbapt
530247841Sbaptvoid
531247841Sbaptconfig_finish(void) {
532247841Sbapt	int i;
533247841Sbapt
534247841Sbapt	for (i = 0; i < CONFIG_SIZE; i++)
535247841Sbapt		free(c[i].value);
536247841Sbapt}
537