2 * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
3 * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
33 #include <sys/elf_common.h>
34 #include <sys/endian.h>
35 #include <sys/types.h>
50 #include "elf_tables.h"
53 #define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
57 STAILQ_ENTRY(config_value) next;
65 STAILQ_HEAD(, config_value) *list;
67 bool main_only; /* Only set in pkg.conf. */
70 static struct config_entry c[] = {
74 URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest",
98 [ASSUME_ALWAYS_YES] = {
146 elf_corres_to_string(struct _elf_corres *m, int e)
150 for (i = 0; m[i].string != NULL; i++)
151 if (m[i].elf_nb == e)
152 return (m[i].string);
158 pkg_get_myabi(char *dest, size_t sz)
176 if (elf_version(EV_CURRENT) == EV_NONE) {
177 warnx("ELF library initialization failed: %s",
182 if ((fd = open(_PATH_BSHELL, O_RDONLY)) < 0) {
187 if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
189 warnx("elf_begin() failed: %s.", elf_errmsg(-1));
193 if (gelf_getehdr(elf, &elfhdr) == NULL) {
195 warn("getehdr() failed: %s.", elf_errmsg(-1));
198 while ((scn = elf_nextscn(elf, scn)) != NULL) {
199 if (gelf_getshdr(scn, &shdr) != &shdr) {
201 warn("getshdr() failed: %s.", elf_errmsg(-1));
205 if (shdr.sh_type == SHT_NOTE)
211 warn("failed to get the note section");
215 data = elf_getdata(scn, NULL);
218 memcpy(¬e, src, sizeof(Elf_Note));
219 src += sizeof(Elf_Note);
220 if (note.n_type == NT_VERSION)
222 src += note.n_namesz + note.n_descsz;
225 src += roundup2(note.n_namesz, 4);
226 if (elfhdr.e_ident[EI_DATA] == ELFDATA2MSB)
227 version = be32dec(src);
229 version = le32dec(src);
231 for (i = 0; osname[i] != '\0'; i++)
232 osname[i] = (char)tolower(osname[i]);
234 snprintf(dest, sz, "%s:%d:%s:%s",
235 osname, version / 100000,
236 elf_corres_to_string(mach_corres, (int)elfhdr.e_machine),
237 elf_corres_to_string(wordsize_corres,
238 (int)elfhdr.e_ident[EI_CLASS]));
242 switch (elfhdr.e_machine) {
244 snprintf(dest + strlen(dest), sz - strlen(dest),
245 ":%s:%s:%s", elf_corres_to_string(endian_corres,
246 (int)elfhdr.e_ident[EI_DATA]),
247 (elfhdr.e_flags & EF_ARM_NEW_ABI) > 0 ?
249 (elfhdr.e_flags & EF_ARM_VFP_FLOAT) > 0 ?
254 * this is taken from binutils sources:
256 * mapping is figured out from binutils:
257 * gas/config/tc-mips.c
259 switch (elfhdr.e_flags & EF_MIPS_ABI) {
267 if (elfhdr.e_ident[EI_DATA] ==
270 else if (elfhdr.e_ident[EI_DATA] ==
275 snprintf(dest + strlen(dest), sz - strlen(dest),
276 ":%s:%s", elf_corres_to_string(endian_corres,
277 (int)elfhdr.e_ident[EI_DATA]), abi);
290 subst_packagesite(const char *abi)
293 const char *variable_string;
296 if (c[PACKAGESITE].value != NULL)
297 oldval = c[PACKAGESITE].value;
299 oldval = c[PACKAGESITE].val;
301 if ((variable_string = strstr(oldval, "${ABI}")) == NULL)
304 newval = sbuf_new_auto();
305 sbuf_bcat(newval, oldval, variable_string - oldval);
306 sbuf_cat(newval, abi);
307 sbuf_cat(newval, variable_string + strlen("${ABI}"));
310 free(c[PACKAGESITE].value);
311 c[PACKAGESITE].value = strdup(sbuf_data(newval));
315 boolstr_to_bool(const char *str)
317 if (str != NULL && (strcasecmp(str, "true") == 0 ||
318 strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
326 config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
328 struct sbuf *buf = sbuf_new_auto();
329 const ucl_object_t *cur, *seq;
330 ucl_object_iter_t it = NULL, itseq = NULL;
331 struct config_entry *temp_config;
332 struct config_value *cv;
337 /* Temporary config for configs that may be disabled. */
338 temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry));
340 while ((cur = ucl_iterate_object(obj, &it, true))) {
341 key = ucl_object_key(cur);
346 if (conftype == CONFFILE_PKG) {
347 for (j = 0; j < strlen(key); ++j)
348 sbuf_putc(buf, key[j]);
350 } else if (conftype == CONFFILE_REPO) {
351 if (strcasecmp(key, "url") == 0)
352 sbuf_cpy(buf, "PACKAGESITE");
353 else if (strcasecmp(key, "mirror_type") == 0)
354 sbuf_cpy(buf, "MIRROR_TYPE");
355 else if (strcasecmp(key, "signature_type") == 0)
356 sbuf_cpy(buf, "SIGNATURE_TYPE");
357 else if (strcasecmp(key, "fingerprints") == 0)
358 sbuf_cpy(buf, "FINGERPRINTS");
359 else if (strcasecmp(key, "pubkey") == 0)
360 sbuf_cpy(buf, "PUBKEY");
361 else if (strcasecmp(key, "enabled") == 0) {
362 if ((cur->type != UCL_BOOLEAN) ||
363 !ucl_object_toboolean(cur))
370 for (i = 0; i < CONFIG_SIZE; i++) {
371 if (strcmp(sbuf_data(buf), c[i].key) == 0)
375 /* Silently skip unknown keys to be future compatible. */
376 if (i == CONFIG_SIZE)
379 /* env has priority over config file */
383 /* Parse sequence value ["item1", "item2"] */
385 case PKG_CONFIG_LIST:
386 if (cur->type != UCL_ARRAY) {
387 warnx("Skipping invalid array "
388 "value for %s.\n", c[i].key);
391 temp_config[i].list =
392 malloc(sizeof(*temp_config[i].list));
393 STAILQ_INIT(temp_config[i].list);
395 while ((seq = ucl_iterate_object(cur, &itseq, true))) {
396 if (seq->type != UCL_STRING)
398 cv = malloc(sizeof(struct config_value));
400 strdup(ucl_object_tostring(seq));
401 STAILQ_INSERT_TAIL(temp_config[i].list, cv,
405 case PKG_CONFIG_BOOL:
406 temp_config[i].value =
407 strdup(ucl_object_toboolean(cur) ? "yes" : "no");
410 /* Normal string value. */
411 temp_config[i].value = strdup(ucl_object_tostring(cur));
416 /* Repo is enabled, copy over all settings from temp_config. */
417 for (i = 0; i < CONFIG_SIZE; i++) {
420 /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
421 if (conftype != CONFFILE_PKG && c[i].main_only == true)
424 case PKG_CONFIG_LIST:
425 c[i].list = temp_config[i].list;
428 c[i].value = temp_config[i].value;
439 * Parse new repo style configs in style:
446 parse_repo_file(ucl_object_t *obj)
448 ucl_object_iter_t it = NULL;
449 const ucl_object_t *cur;
452 while ((cur = ucl_iterate_object(obj, &it, true))) {
453 key = ucl_object_key(cur);
458 if (cur->type != UCL_OBJECT)
461 config_parse(cur, CONFFILE_REPO);
467 read_conf_file(const char *confpath, pkg_conf_file_t conftype)
469 struct ucl_parser *p;
470 ucl_object_t *obj = NULL;
472 p = ucl_parser_new(0);
474 if (!ucl_parser_add_file(p, confpath)) {
476 errx(EXIT_FAILURE, "Unable to parse configuration "
477 "file %s: %s", confpath, ucl_parser_get_error(p));
479 /* no configuration present */
483 obj = ucl_parser_get_object(p);
484 if (obj->type != UCL_OBJECT)
485 warnx("Invalid configuration format, ignoring the "
486 "configuration file %s", confpath);
488 if (conftype == CONFFILE_PKG)
489 config_parse(obj, conftype);
490 else if (conftype == CONFFILE_REPO)
491 parse_repo_file(obj);
494 ucl_object_unref(obj);
501 load_repositories(const char *repodir)
507 char path[MAXPATHLEN];
512 if ((d = opendir(repodir)) == NULL)
515 while ((ent = readdir(d))) {
516 /* Trim out 'repos'. */
517 if ((n = strlen(ent->d_name)) <= 5)
519 p = &ent->d_name[n - 5];
520 if (strcmp(p, ".conf") == 0) {
521 snprintf(path, sizeof(path), "%s%s%s",
523 repodir[strlen(repodir) - 1] == '/' ? "" : "/",
525 if (access(path, F_OK) == 0 &&
526 read_conf_file(path, CONFFILE_REPO)) {
544 const char *localbase;
546 char confpath[MAXPATHLEN];
547 struct config_value *cv;
550 for (i = 0; i < CONFIG_SIZE; i++) {
551 val = getenv(c[i].key);
555 case PKG_CONFIG_LIST:
556 /* Split up comma-separated items from env. */
557 c[i].list = malloc(sizeof(*c[i].list));
558 STAILQ_INIT(c[i].list);
559 for (env_list_item = strtok(val, ",");
560 env_list_item != NULL;
561 env_list_item = strtok(NULL, ",")) {
563 malloc(sizeof(struct config_value));
565 strdup(env_list_item);
566 STAILQ_INSERT_TAIL(c[i].list, cv,
577 /* Read LOCALBASE/etc/pkg.conf first. */
578 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE;
579 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf",
582 if (access(confpath, F_OK) == 0 && read_conf_file(confpath,
586 /* Then read in all repos from REPOS_DIR list of directories. */
587 if (c[REPOS_DIR].list == NULL) {
588 c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
589 STAILQ_INIT(c[REPOS_DIR].list);
590 cv = malloc(sizeof(struct config_value));
591 cv->value = strdup("/etc/pkg");
592 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
593 cv = malloc(sizeof(struct config_value));
594 if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
596 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
599 STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
600 if (load_repositories(cv->value))
604 if (c[ABI].val == NULL && c[ABI].value == NULL) {
605 if (pkg_get_myabi(abi, BUFSIZ) != 0)
606 errx(EXIT_FAILURE, "Failed to determine the system "
611 subst_packagesite(c[ABI].val);
617 config_string(pkg_config_key k, const char **val)
619 if (c[k].type != PKG_CONFIG_STRING)
622 if (c[k].value != NULL)
631 config_bool(pkg_config_key k, bool *val)
635 if (c[k].type != PKG_CONFIG_BOOL)
640 if (c[k].value != NULL)
645 if (boolstr_to_bool(value))
652 config_finish(void) {
655 for (i = 0; i < CONFIG_SIZE; i++)