1247841Sbapt/*-
2263038Sbapt * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
3263038Sbapt * 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>
32247841Sbapt#include <sys/sbuf.h>
33247841Sbapt#include <sys/elf_common.h>
34247841Sbapt#include <sys/endian.h>
35263038Sbapt#include <sys/types.h>
36247841Sbapt
37263038Sbapt#include <dirent.h>
38263038Sbapt#include <ucl.h>
39247841Sbapt#include <ctype.h>
40247841Sbapt#include <err.h>
41247841Sbapt#include <errno.h>
42247841Sbapt#include <fcntl.h>
43247841Sbapt#include <gelf.h>
44247841Sbapt#include <inttypes.h>
45247841Sbapt#include <paths.h>
46247841Sbapt#include <stdbool.h>
47247841Sbapt#include <string.h>
48247841Sbapt#include <unistd.h>
49247841Sbapt
50247841Sbapt#include "elf_tables.h"
51247841Sbapt#include "config.h"
52247841Sbapt
53247841Sbapt#define roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
54247841Sbapt
55263038Sbaptstruct config_value {
56263038Sbapt       char *value;
57263038Sbapt       STAILQ_ENTRY(config_value) next;
58263038Sbapt};
59263038Sbapt
60247841Sbaptstruct config_entry {
61247841Sbapt	uint8_t type;
62247841Sbapt	const char *key;
63247841Sbapt	const char *val;
64247841Sbapt	char *value;
65263038Sbapt	STAILQ_HEAD(, config_value) *list;
66247841Sbapt	bool envset;
67263623Sbdrewery	bool main_only;				/* Only set in pkg.conf. */
68247841Sbapt};
69247841Sbapt
70247841Sbaptstatic struct config_entry c[] = {
71247841Sbapt	[PACKAGESITE] = {
72247841Sbapt		PKG_CONFIG_STRING,
73247841Sbapt		"PACKAGESITE",
74263038Sbapt		URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest",
75247841Sbapt		NULL,
76263038Sbapt		NULL,
77247841Sbapt		false,
78263623Sbdrewery		false,
79247841Sbapt	},
80247841Sbapt	[ABI] = {
81247841Sbapt		PKG_CONFIG_STRING,
82247841Sbapt		"ABI",
83247841Sbapt		NULL,
84247841Sbapt		NULL,
85263038Sbapt		NULL,
86247841Sbapt		false,
87263623Sbdrewery		true,
88247841Sbapt	},
89247841Sbapt	[MIRROR_TYPE] = {
90247841Sbapt		PKG_CONFIG_STRING,
91247841Sbapt		"MIRROR_TYPE",
92247841Sbapt		"SRV",
93247841Sbapt		NULL,
94263038Sbapt		NULL,
95247841Sbapt		false,
96263623Sbdrewery		false,
97247841Sbapt	},
98247841Sbapt	[ASSUME_ALWAYS_YES] = {
99247841Sbapt		PKG_CONFIG_BOOL,
100247841Sbapt		"ASSUME_ALWAYS_YES",
101247841Sbapt		"NO",
102247841Sbapt		NULL,
103263038Sbapt		NULL,
104247841Sbapt		false,
105263623Sbdrewery		true,
106263038Sbapt	},
107263038Sbapt	[SIGNATURE_TYPE] = {
108263038Sbapt		PKG_CONFIG_STRING,
109263038Sbapt		"SIGNATURE_TYPE",
110263038Sbapt		NULL,
111263038Sbapt		NULL,
112263038Sbapt		NULL,
113263038Sbapt		false,
114263623Sbdrewery		false,
115263038Sbapt	},
116263038Sbapt	[FINGERPRINTS] = {
117263038Sbapt		PKG_CONFIG_STRING,
118263038Sbapt		"FINGERPRINTS",
119263038Sbapt		NULL,
120263038Sbapt		NULL,
121263038Sbapt		NULL,
122263038Sbapt		false,
123263623Sbdrewery		false,
124263038Sbapt	},
125263038Sbapt	[REPOS_DIR] = {
126263038Sbapt		PKG_CONFIG_LIST,
127263038Sbapt		"REPOS_DIR",
128263038Sbapt		NULL,
129263038Sbapt		NULL,
130263038Sbapt		NULL,
131263038Sbapt		false,
132263623Sbdrewery		true,
133263038Sbapt	},
134287873Sdelphij	[PUBKEY] = {
135287873Sdelphij		PKG_CONFIG_STRING,
136287873Sdelphij		"PUBKEY",
137287873Sdelphij		NULL,
138287873Sdelphij		NULL,
139287873Sdelphij		NULL,
140287873Sdelphij		false,
141287873Sdelphij		false
142287873Sdelphij	}
143247841Sbapt};
144247841Sbapt
145247841Sbaptstatic const char *
146247841Sbaptelf_corres_to_string(struct _elf_corres *m, int e)
147247841Sbapt{
148247841Sbapt	int i;
149247841Sbapt
150247841Sbapt	for (i = 0; m[i].string != NULL; i++)
151247841Sbapt		if (m[i].elf_nb == e)
152247841Sbapt			return (m[i].string);
153247841Sbapt
154247841Sbapt	return ("unknown");
155247841Sbapt}
156247841Sbapt
157247841Sbaptstatic int
158247841Sbaptpkg_get_myabi(char *dest, size_t sz)
159247841Sbapt{
160247841Sbapt	Elf *elf;
161247841Sbapt	Elf_Data *data;
162247841Sbapt	Elf_Note note;
163247841Sbapt	Elf_Scn *scn;
164247841Sbapt	char *src, *osname;
165247841Sbapt	const char *abi;
166247841Sbapt	GElf_Ehdr elfhdr;
167247841Sbapt	GElf_Shdr shdr;
168247841Sbapt	int fd, i, ret;
169247841Sbapt	uint32_t version;
170247841Sbapt
171247841Sbapt	version = 0;
172247841Sbapt	ret = -1;
173247841Sbapt	scn = NULL;
174247841Sbapt	abi = NULL;
175247841Sbapt
176247841Sbapt	if (elf_version(EV_CURRENT) == EV_NONE) {
177247841Sbapt		warnx("ELF library initialization failed: %s",
178247841Sbapt		    elf_errmsg(-1));
179247841Sbapt		return (-1);
180247841Sbapt	}
181247841Sbapt
182247841Sbapt	if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) {
183247841Sbapt		warn("open()");
184247841Sbapt		return (-1);
185247841Sbapt	}
186247841Sbapt
187247841Sbapt	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
188247841Sbapt		ret = -1;
189247841Sbapt		warnx("elf_begin() failed: %s.", elf_errmsg(-1));
190247841Sbapt		goto cleanup;
191247841Sbapt	}
192247841Sbapt
193247841Sbapt	if (gelf_getehdr(elf, &elfhdr) == NULL) {
194247841Sbapt		ret = -1;
195247841Sbapt		warn("getehdr() failed: %s.", elf_errmsg(-1));
196247841Sbapt		goto cleanup;
197247841Sbapt	}
198247841Sbapt	while ((scn = elf_nextscn(elf, scn)) != NULL) {
199247841Sbapt		if (gelf_getshdr(scn, &shdr) != &shdr) {
200247841Sbapt			ret = -1;
201247841Sbapt			warn("getshdr() failed: %s.", elf_errmsg(-1));
202247841Sbapt			goto cleanup;
203247841Sbapt		}
204247841Sbapt
205247841Sbapt		if (shdr.sh_type == SHT_NOTE)
206247841Sbapt			break;
207247841Sbapt	}
208247841Sbapt
209247841Sbapt	if (scn == NULL) {
210247841Sbapt		ret = -1;
211247841Sbapt		warn("failed to get the note section");
212247841Sbapt		goto cleanup;
213247841Sbapt	}
214247841Sbapt
215247841Sbapt	data = elf_getdata(scn, NULL);
216247841Sbapt	src = data->d_buf;
217247841Sbapt	for (;;) {
218247841Sbapt		memcpy(&note, src, sizeof(Elf_Note));
219247841Sbapt		src += sizeof(Elf_Note);
220247841Sbapt		if (note.n_type == NT_VERSION)
221247841Sbapt			break;
222247841Sbapt		src += note.n_namesz + note.n_descsz;
223247841Sbapt	}
224247841Sbapt	osname = src;
225247841Sbapt	src += roundup2(note.n_namesz, 4);
226247841Sbapt	if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
227247841Sbapt		version = be32dec(src);
228247841Sbapt	else
229247841Sbapt		version = le32dec(src);
230247841Sbapt
231247841Sbapt	for (i = 0; osname[i] != '\0'; i++)
232247841Sbapt		osname[i] = (char)tolower(osname[i]);
233247841Sbapt
234247841Sbapt	snprintf(dest, sz, "%s:%d:%s:%s",
235247841Sbapt	    osname, version / 100000,
236247841Sbapt	    elf_corres_to_string(mach_corres, (int)elfhdr.e_machine),
237247841Sbapt	    elf_corres_to_string(wordsize_corres,
238247841Sbapt	    (int)elfhdr.e_ident[EI_CLASS]));
239247841Sbapt
240247841Sbapt	ret = 0;
241247841Sbapt
242247841Sbapt	switch (elfhdr.e_machine) {
243247841Sbapt	case EM_ARM:
244247841Sbapt		snprintf(dest + strlen(dest), sz - strlen(dest),
245247841Sbapt		    ":%s:%s:%s", elf_corres_to_string(endian_corres,
246247841Sbapt		    (int)elfhdr.e_ident[EI_DATA]),
247247841Sbapt		    (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ?
248247841Sbapt		    "eabi" : "oabi",
249247841Sbapt		    (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ?
250247841Sbapt		    "softfp" : "vfp");
251247841Sbapt		break;
252247841Sbapt	case EM_MIPS:
253247841Sbapt		/*
254247841Sbapt		 * this is taken from binutils sources:
255247841Sbapt		 * include/elf/mips.h
256247841Sbapt		 * mapping is figured out from binutils:
257247841Sbapt		 * gas/config/tc-mips.c
258247841Sbapt		 */
259247841Sbapt		switch (elfhdr.e_flags & EF_MIPS_ABI) {
260247841Sbapt		case E_MIPS_ABI_O32:
261247841Sbapt			abi = "o32";
262247841Sbapt			break;
263247841Sbapt		case E_MIPS_ABI_N32:
264247841Sbapt			abi = "n32";
265247841Sbapt			break;
266247841Sbapt		default:
267247841Sbapt			if (elfhdr.e_ident[EI_DATA] ==
268247841Sbapt			    ELFCLASS32)
269247841Sbapt				abi = "o32";
270247841Sbapt			else if (elfhdr.e_ident[EI_DATA] ==
271247841Sbapt			    ELFCLASS64)
272247841Sbapt				abi = "n64";
273247841Sbapt			break;
274247841Sbapt		}
275247841Sbapt		snprintf(dest + strlen(dest), sz - strlen(dest),
276247841Sbapt		    ":%s:%s", elf_corres_to_string(endian_corres,
277247841Sbapt		    (int)elfhdr.e_ident[EI_DATA]), abi);
278247841Sbapt		break;
279247841Sbapt	}
280247841Sbapt
281247841Sbaptcleanup:
282247841Sbapt	if (elf != NULL)
283247841Sbapt		elf_end(elf);
284247841Sbapt
285247841Sbapt	close(fd);
286247841Sbapt	return (ret);
287247841Sbapt}
288247841Sbapt
289247841Sbaptstatic void
290247841Sbaptsubst_packagesite(const char *abi)
291247841Sbapt{
292247841Sbapt	struct sbuf *newval;
293247841Sbapt	const char *variable_string;
294247841Sbapt	const char *oldval;
295247841Sbapt
296247841Sbapt	if (c[PACKAGESITE].value != NULL)
297247841Sbapt		oldval = c[PACKAGESITE].value;
298247841Sbapt	else
299247841Sbapt		oldval = c[PACKAGESITE].val;
300247841Sbapt
301247841Sbapt	if ((variable_string = strstr(oldval, "${ABI}")) == NULL)
302247841Sbapt		return;
303247841Sbapt
304247841Sbapt	newval = sbuf_new_auto();
305247841Sbapt	sbuf_bcat(newval, oldval, variable_string - oldval);
306247841Sbapt	sbuf_cat(newval, abi);
307247841Sbapt	sbuf_cat(newval, variable_string + strlen("${ABI}"));
308247841Sbapt	sbuf_finish(newval);
309247841Sbapt
310247841Sbapt	free(c[PACKAGESITE].value);
311247841Sbapt	c[PACKAGESITE].value = strdup(sbuf_data(newval));
312247841Sbapt}
313247841Sbapt
314263038Sbaptstatic int
315263038Sbaptboolstr_to_bool(const char *str)
316263038Sbapt{
317263038Sbapt	if (str != NULL && (strcasecmp(str, "true") == 0 ||
318263038Sbapt	    strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
319263038Sbapt	    str[0] == '1'))
320263038Sbapt		return (true);
321263038Sbapt
322263038Sbapt	return (false);
323263038Sbapt}
324263038Sbapt
325247841Sbaptstatic void
326263038Sbaptconfig_parse(ucl_object_t *obj, pkg_conf_file_t conftype)
327247841Sbapt{
328247841Sbapt	struct sbuf *buf = sbuf_new_auto();
329263038Sbapt	ucl_object_t *cur, *seq;
330263038Sbapt	ucl_object_iter_t it = NULL, itseq = NULL;
331263038Sbapt	struct config_entry *temp_config;
332263038Sbapt	struct config_value *cv;
333263038Sbapt	const char *key;
334247841Sbapt	int i;
335247841Sbapt	size_t j;
336247841Sbapt
337263038Sbapt	/* Temporary config for configs that may be disabled. */
338263038Sbapt	temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry));
339247841Sbapt
340263038Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
341263038Sbapt		key = ucl_object_key(cur);
342263038Sbapt		if (key == NULL)
343247841Sbapt			continue;
344263038Sbapt		sbuf_clear(buf);
345247841Sbapt
346263038Sbapt		if (conftype == CONFFILE_PKG) {
347263038Sbapt			for (j = 0; j < strlen(key); ++j)
348263038Sbapt				sbuf_putc(buf, key[j]);
349263038Sbapt			sbuf_finish(buf);
350263038Sbapt		} else if (conftype == CONFFILE_REPO) {
351263038Sbapt			if (strcasecmp(key, "url") == 0)
352263038Sbapt				sbuf_cpy(buf, "PACKAGESITE");
353263038Sbapt			else if (strcasecmp(key, "mirror_type") == 0)
354263038Sbapt				sbuf_cpy(buf, "MIRROR_TYPE");
355263038Sbapt			else if (strcasecmp(key, "signature_type") == 0)
356263038Sbapt				sbuf_cpy(buf, "SIGNATURE_TYPE");
357263038Sbapt			else if (strcasecmp(key, "fingerprints") == 0)
358263038Sbapt				sbuf_cpy(buf, "FINGERPRINTS");
359287873Sdelphij			else if (strcasecmp(key, "pubkey") == 0)
360287873Sdelphij				sbuf_cpy(buf, "PUBKEY");
361263038Sbapt			else if (strcasecmp(key, "enabled") == 0) {
362263038Sbapt				if ((cur->type != UCL_BOOLEAN) ||
363263038Sbapt				    !ucl_object_toboolean(cur))
364263038Sbapt					goto cleanup;
365263038Sbapt			} else
366263038Sbapt				continue;
367263038Sbapt			sbuf_finish(buf);
368247841Sbapt		}
369247841Sbapt
370247841Sbapt		for (i = 0; i < CONFIG_SIZE; i++) {
371247841Sbapt			if (strcmp(sbuf_data(buf), c[i].key) == 0)
372247841Sbapt				break;
373247841Sbapt		}
374247841Sbapt
375263038Sbapt		/* Silently skip unknown keys to be future compatible. */
376263038Sbapt		if (i == CONFIG_SIZE)
377247841Sbapt			continue;
378247841Sbapt
379247841Sbapt		/* env has priority over config file */
380263038Sbapt		if (c[i].envset)
381247841Sbapt			continue;
382263038Sbapt
383263038Sbapt		/* Parse sequence value ["item1", "item2"] */
384263038Sbapt		switch (c[i].type) {
385263038Sbapt		case PKG_CONFIG_LIST:
386263038Sbapt			if (cur->type != UCL_ARRAY) {
387263038Sbapt				warnx("Skipping invalid array "
388263038Sbapt				    "value for %s.\n", c[i].key);
389263038Sbapt				continue;
390263038Sbapt			}
391263038Sbapt			temp_config[i].list =
392263038Sbapt			    malloc(sizeof(*temp_config[i].list));
393263038Sbapt			STAILQ_INIT(temp_config[i].list);
394263038Sbapt
395263038Sbapt			while ((seq = ucl_iterate_object(cur, &itseq, true))) {
396263038Sbapt				if (seq->type != UCL_STRING)
397263038Sbapt					continue;
398263038Sbapt				cv = malloc(sizeof(struct config_value));
399263038Sbapt				cv->value =
400263038Sbapt				    strdup(ucl_object_tostring(seq));
401263038Sbapt				STAILQ_INSERT_TAIL(temp_config[i].list, cv,
402263038Sbapt				    next);
403263038Sbapt			}
404263038Sbapt			break;
405263627Sbdrewery		case PKG_CONFIG_BOOL:
406263627Sbdrewery			temp_config[i].value =
407263627Sbdrewery			    strdup(ucl_object_toboolean(cur) ? "yes" : "no");
408263627Sbdrewery			break;
409263038Sbapt		default:
410263038Sbapt			/* Normal string value. */
411263038Sbapt			temp_config[i].value = strdup(ucl_object_tostring(cur));
412263038Sbapt			break;
413247841Sbapt		}
414263038Sbapt	}
415247841Sbapt
416263038Sbapt	/* Repo is enabled, copy over all settings from temp_config. */
417263038Sbapt	for (i = 0; i < CONFIG_SIZE; i++) {
418263038Sbapt		if (c[i].envset)
419263038Sbapt			continue;
420263623Sbdrewery		/* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
421263623Sbdrewery		if (conftype != CONFFILE_PKG && c[i].main_only == true)
422263623Sbdrewery			continue;
423263038Sbapt		switch (c[i].type) {
424263038Sbapt		case PKG_CONFIG_LIST:
425263038Sbapt			c[i].list = temp_config[i].list;
426263038Sbapt			break;
427263038Sbapt		default:
428263038Sbapt			c[i].value = temp_config[i].value;
429263038Sbapt			break;
430263038Sbapt		}
431247841Sbapt	}
432247841Sbapt
433263038Sbaptcleanup:
434263038Sbapt	free(temp_config);
435247841Sbapt	sbuf_delete(buf);
436247841Sbapt}
437247841Sbapt
438263038Sbapt/*-
439263038Sbapt * Parse new repo style configs in style:
440263038Sbapt * Name:
441263038Sbapt *   URL:
442263038Sbapt *   MIRROR_TYPE:
443263038Sbapt * etc...
444263038Sbapt */
445263038Sbaptstatic void
446263038Sbaptparse_repo_file(ucl_object_t *obj)
447263038Sbapt{
448263038Sbapt	ucl_object_iter_t it = NULL;
449263038Sbapt	ucl_object_t *cur;
450263038Sbapt	const char *key;
451263038Sbapt
452263038Sbapt	while ((cur = ucl_iterate_object(obj, &it, true))) {
453263038Sbapt		key = ucl_object_key(cur);
454263038Sbapt
455263038Sbapt		if (key == NULL)
456263038Sbapt			continue;
457263038Sbapt
458263038Sbapt		if (cur->type != UCL_OBJECT)
459263038Sbapt			continue;
460263038Sbapt
461263038Sbapt		config_parse(cur, CONFFILE_REPO);
462263038Sbapt	}
463263038Sbapt}
464263038Sbapt
465263038Sbapt
466263038Sbaptstatic int
467263038Sbaptread_conf_file(const char *confpath, pkg_conf_file_t conftype)
468263038Sbapt{
469263038Sbapt	struct ucl_parser *p;
470263038Sbapt	ucl_object_t *obj = NULL;
471263038Sbapt
472263038Sbapt	p = ucl_parser_new(0);
473263038Sbapt
474263038Sbapt	if (!ucl_parser_add_file(p, confpath)) {
475263038Sbapt		if (errno != ENOENT)
476263038Sbapt			errx(EXIT_FAILURE, "Unable to parse configuration "
477263038Sbapt			    "file %s: %s", confpath, ucl_parser_get_error(p));
478263038Sbapt		ucl_parser_free(p);
479263038Sbapt		/* no configuration present */
480263038Sbapt		return (1);
481263038Sbapt	}
482263038Sbapt
483263038Sbapt	obj = ucl_parser_get_object(p);
484263038Sbapt	if (obj->type != UCL_OBJECT)
485263038Sbapt		warnx("Invalid configuration format, ignoring the "
486263038Sbapt		    "configuration file %s", confpath);
487263038Sbapt	else {
488263038Sbapt		if (conftype == CONFFILE_PKG)
489263038Sbapt			config_parse(obj, conftype);
490263038Sbapt		else if (conftype == CONFFILE_REPO)
491263038Sbapt			parse_repo_file(obj);
492263038Sbapt	}
493263038Sbapt
494263038Sbapt	ucl_object_free(obj);
495263038Sbapt	ucl_parser_free(p);
496263038Sbapt
497263038Sbapt	return (0);
498263038Sbapt}
499263038Sbapt
500263038Sbaptstatic int
501263038Sbaptload_repositories(const char *repodir)
502263038Sbapt{
503263038Sbapt	struct dirent *ent;
504263038Sbapt	DIR *d;
505263038Sbapt	char *p;
506263038Sbapt	size_t n;
507263038Sbapt	char path[MAXPATHLEN];
508263038Sbapt	int ret;
509263038Sbapt
510263038Sbapt	ret = 0;
511263038Sbapt
512263038Sbapt	if ((d = opendir(repodir)) == NULL)
513263038Sbapt		return (1);
514263038Sbapt
515263038Sbapt	while ((ent = readdir(d))) {
516263038Sbapt		/* Trim out 'repos'. */
517263038Sbapt		if ((n = strlen(ent->d_name)) <= 5)
518263038Sbapt			continue;
519263038Sbapt		p = &ent->d_name[n - 5];
520263038Sbapt		if (strcmp(p, ".conf") == 0) {
521263038Sbapt			snprintf(path, sizeof(path), "%s%s%s",
522263038Sbapt			    repodir,
523263038Sbapt			    repodir[strlen(repodir) - 1] == '/' ? "" : "/",
524263038Sbapt			    ent->d_name);
525263038Sbapt			if (access(path, F_OK) == 0 &&
526263038Sbapt			    read_conf_file(path, CONFFILE_REPO)) {
527263038Sbapt				ret = 1;
528263038Sbapt				goto cleanup;
529263038Sbapt			}
530263038Sbapt		}
531263038Sbapt	}
532263038Sbapt
533263038Sbaptcleanup:
534263038Sbapt	closedir(d);
535263038Sbapt
536263038Sbapt	return (ret);
537263038Sbapt}
538263038Sbapt
539247841Sbaptint
540247841Sbaptconfig_init(void)
541247841Sbapt{
542263038Sbapt	char *val;
543247841Sbapt	int i;
544247841Sbapt	const char *localbase;
545263038Sbapt	char *env_list_item;
546247841Sbapt	char confpath[MAXPATHLEN];
547263038Sbapt	struct config_value *cv;
548247841Sbapt	char abi[BUFSIZ];
549247841Sbapt
550247841Sbapt	for (i = 0; i < CONFIG_SIZE; i++) {
551247841Sbapt		val = getenv(c[i].key);
552247841Sbapt		if (val != NULL) {
553247841Sbapt			c[i].envset = true;
554263038Sbapt			switch (c[i].type) {
555263038Sbapt			case PKG_CONFIG_LIST:
556263038Sbapt				/* Split up comma-separated items from env. */
557263038Sbapt				c[i].list = malloc(sizeof(*c[i].list));
558263038Sbapt				STAILQ_INIT(c[i].list);
559263038Sbapt				for (env_list_item = strtok(val, ",");
560263038Sbapt				    env_list_item != NULL;
561263038Sbapt				    env_list_item = strtok(NULL, ",")) {
562263038Sbapt					cv =
563263038Sbapt					    malloc(sizeof(struct config_value));
564263038Sbapt					cv->value =
565263038Sbapt					    strdup(env_list_item);
566263038Sbapt					STAILQ_INSERT_TAIL(c[i].list, cv,
567263038Sbapt					    next);
568263038Sbapt				}
569263038Sbapt				break;
570263038Sbapt			default:
571263038Sbapt				c[i].val = val;
572263038Sbapt				break;
573263038Sbapt			}
574247841Sbapt		}
575247841Sbapt	}
576247841Sbapt
577263038Sbapt	/* Read LOCALBASE/etc/pkg.conf first. */
578247841Sbapt	localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE;
579263038Sbapt	snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf",
580263038Sbapt	    localbase);
581247841Sbapt
582263038Sbapt	if (access(confpath, F_OK) == 0 && read_conf_file(confpath,
583263038Sbapt	    CONFFILE_PKG))
584247841Sbapt		goto finalize;
585247841Sbapt
586263038Sbapt	/* Then read in all repos from REPOS_DIR list of directories. */
587263038Sbapt	if (c[REPOS_DIR].list == NULL) {
588263038Sbapt		c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
589263038Sbapt		STAILQ_INIT(c[REPOS_DIR].list);
590263038Sbapt		cv = malloc(sizeof(struct config_value));
591263038Sbapt		cv->value = strdup("/etc/pkg");
592263038Sbapt		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
593263038Sbapt		cv = malloc(sizeof(struct config_value));
594263038Sbapt		if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
595263038Sbapt			goto finalize;
596263038Sbapt		STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
597247841Sbapt	}
598247841Sbapt
599263038Sbapt	STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
600263038Sbapt		if (load_repositories(cv->value))
601263038Sbapt			goto finalize;
602247841Sbapt
603247841Sbaptfinalize:
604247841Sbapt	if (c[ABI].val == NULL && c[ABI].value == NULL) {
605247841Sbapt		if (pkg_get_myabi(abi, BUFSIZ) != 0)
606263038Sbapt			errx(EXIT_FAILURE, "Failed to determine the system "
607263038Sbapt			    "ABI");
608247841Sbapt		c[ABI].val = abi;
609247841Sbapt	}
610247841Sbapt
611247841Sbapt	subst_packagesite(c[ABI].val);
612247841Sbapt
613247841Sbapt	return (0);
614247841Sbapt}
615247841Sbapt
616247841Sbaptint
617247841Sbaptconfig_string(pkg_config_key k, const char **val)
618247841Sbapt{
619247841Sbapt	if (c[k].type != PKG_CONFIG_STRING)
620247841Sbapt		return (-1);
621247841Sbapt
622247841Sbapt	if (c[k].value != NULL)
623247841Sbapt		*val = c[k].value;
624247841Sbapt	else
625247841Sbapt		*val = c[k].val;
626247841Sbapt
627247841Sbapt	return (0);
628247841Sbapt}
629247841Sbapt
630247841Sbaptint
631247841Sbaptconfig_bool(pkg_config_key k, bool *val)
632247841Sbapt{
633247841Sbapt	const char *value;
634247841Sbapt
635247841Sbapt	if (c[k].type != PKG_CONFIG_BOOL)
636247841Sbapt		return (-1);
637247841Sbapt
638247841Sbapt	*val = false;
639247841Sbapt
640247841Sbapt	if (c[k].value != NULL)
641247841Sbapt		value = c[k].value;
642247841Sbapt	else
643247841Sbapt		value = c[k].val;
644247841Sbapt
645263038Sbapt	if (boolstr_to_bool(value))
646247841Sbapt		*val = true;
647247841Sbapt
648247841Sbapt	return (0);
649247841Sbapt}
650247841Sbapt
651247841Sbaptvoid
652247841Sbaptconfig_finish(void) {
653247841Sbapt	int i;
654247841Sbapt
655247841Sbapt	for (i = 0; i < CONFIG_SIZE; i++)
656247841Sbapt		free(c[i].value);
657247841Sbapt}
658