2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
5 * Copyright (c) 2013 Bryan Drewery <bdrewery@FreeBSD.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/queue.h>
35 #include <sys/utsname.h>
37 #include <sys/sysctl.h>
51 STAILQ_ENTRY(config_value) next;
59 STAILQ_HEAD(, config_value) *list;
61 bool main_only; /* Only set in pkg.conf. */
64 static struct config_entry c[] = {
68 URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest",
92 [ASSUME_ALWAYS_YES] = {
149 pkg_get_myabi(char *dest, size_t sz)
152 char machine_arch[255];
160 len = sizeof(machine_arch);
161 error = sysctlbyname("hw.machine_arch", machine_arch, &len, NULL, 0);
164 machine_arch[len] = '\0';
167 * Use __FreeBSD_version rather than kernel version (uts.release) for
168 * use in jails. This is equivalent to the value of uname -U.
170 snprintf(dest, sz, "%s:%d:%s", uts.sysname, __FreeBSD_version/100000,
177 subst_packagesite(const char *abi)
180 const char *variable_string;
183 if (c[PACKAGESITE].value != NULL)
184 oldval = c[PACKAGESITE].value;
186 oldval = c[PACKAGESITE].val;
188 if ((variable_string = strstr(oldval, "${ABI}")) == NULL)
191 asprintf(&newval, "%.*s%s%s",
192 (int)(variable_string - oldval), oldval, abi,
193 variable_string + strlen("${ABI}"));
195 errx(EXIT_FAILURE, "asprintf");
197 free(c[PACKAGESITE].value);
198 c[PACKAGESITE].value = newval;
202 boolstr_to_bool(const char *str)
204 if (str != NULL && (strcasecmp(str, "true") == 0 ||
205 strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
213 config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
215 struct sbuf *buf = sbuf_new_auto();
216 const ucl_object_t *cur, *seq, *tmp;
217 ucl_object_iter_t it = NULL, itseq = NULL, it_obj = NULL;
218 struct config_entry *temp_config;
219 struct config_value *cv;
220 const char *key, *evkey;
224 /* Temporary config for configs that may be disabled. */
225 temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry));
227 while ((cur = ucl_iterate_object(obj, &it, true))) {
228 key = ucl_object_key(cur);
233 if (conftype == CONFFILE_PKG) {
234 for (j = 0; j < strlen(key); ++j)
235 sbuf_putc(buf, toupper(key[j]));
237 } else if (conftype == CONFFILE_REPO) {
238 if (strcasecmp(key, "url") == 0)
239 sbuf_cpy(buf, "PACKAGESITE");
240 else if (strcasecmp(key, "mirror_type") == 0)
241 sbuf_cpy(buf, "MIRROR_TYPE");
242 else if (strcasecmp(key, "signature_type") == 0)
243 sbuf_cpy(buf, "SIGNATURE_TYPE");
244 else if (strcasecmp(key, "fingerprints") == 0)
245 sbuf_cpy(buf, "FINGERPRINTS");
246 else if (strcasecmp(key, "pubkey") == 0)
247 sbuf_cpy(buf, "PUBKEY");
248 else if (strcasecmp(key, "enabled") == 0) {
249 if ((cur->type != UCL_BOOLEAN) ||
250 !ucl_object_toboolean(cur))
257 for (i = 0; i < CONFIG_SIZE; i++) {
258 if (strcmp(sbuf_data(buf), c[i].key) == 0)
262 /* Silently skip unknown keys to be future compatible. */
263 if (i == CONFIG_SIZE)
266 /* env has priority over config file */
270 /* Parse sequence value ["item1", "item2"] */
272 case PKG_CONFIG_LIST:
273 if (cur->type != UCL_ARRAY) {
274 warnx("Skipping invalid array "
275 "value for %s.\n", c[i].key);
278 temp_config[i].list =
279 malloc(sizeof(*temp_config[i].list));
280 STAILQ_INIT(temp_config[i].list);
282 while ((seq = ucl_iterate_object(cur, &itseq, true))) {
283 if (seq->type != UCL_STRING)
285 cv = malloc(sizeof(struct config_value));
287 strdup(ucl_object_tostring(seq));
288 STAILQ_INSERT_TAIL(temp_config[i].list, cv,
292 case PKG_CONFIG_BOOL:
293 temp_config[i].value =
294 strdup(ucl_object_toboolean(cur) ? "yes" : "no");
296 case PKG_CONFIG_OBJECT:
297 if (strcmp(c[i].key, "PKG_ENV") == 0) {
299 ucl_iterate_object(cur, &it_obj, true))) {
300 evkey = ucl_object_key(tmp);
301 if (evkey != NULL && *evkey != '\0') {
302 setenv(evkey, ucl_object_tostring_forced(tmp), 1);
308 /* Normal string value. */
309 temp_config[i].value = strdup(ucl_object_tostring(cur));
314 /* Repo is enabled, copy over all settings from temp_config. */
315 for (i = 0; i < CONFIG_SIZE; i++) {
318 /* Prevent overriding ABI, ASSUME_ALWAYS_YES, etc. */
319 if (conftype != CONFFILE_PKG && c[i].main_only == true)
322 case PKG_CONFIG_LIST:
323 c[i].list = temp_config[i].list;
326 c[i].value = temp_config[i].value;
337 * Parse new repo style configs in style:
344 parse_repo_file(ucl_object_t *obj, const char *requested_repo)
346 ucl_object_iter_t it = NULL;
347 const ucl_object_t *cur;
350 while ((cur = ucl_iterate_object(obj, &it, true))) {
351 key = ucl_object_key(cur);
356 if (cur->type != UCL_OBJECT)
359 if (requested_repo != NULL && strcmp(requested_repo, key) != 0)
362 config_parse(cur, CONFFILE_REPO);
368 read_conf_file(const char *confpath, const char *requested_repo,
369 pkg_conf_file_t conftype)
371 struct ucl_parser *p;
372 ucl_object_t *obj = NULL;
374 p = ucl_parser_new(0);
376 if (!ucl_parser_add_file(p, confpath)) {
378 errx(EXIT_FAILURE, "Unable to parse configuration "
379 "file %s: %s", confpath, ucl_parser_get_error(p));
381 /* no configuration present */
385 obj = ucl_parser_get_object(p);
386 if (obj->type != UCL_OBJECT)
387 warnx("Invalid configuration format, ignoring the "
388 "configuration file %s", confpath);
390 if (conftype == CONFFILE_PKG)
391 config_parse(obj, conftype);
392 else if (conftype == CONFFILE_REPO)
393 parse_repo_file(obj, requested_repo);
396 ucl_object_unref(obj);
403 load_repositories(const char *repodir, const char *requested_repo)
409 char path[MAXPATHLEN];
414 if ((d = opendir(repodir)) == NULL)
417 while ((ent = readdir(d))) {
418 /* Trim out 'repos'. */
419 if ((n = strlen(ent->d_name)) <= 5)
421 p = &ent->d_name[n - 5];
422 if (strcmp(p, ".conf") == 0) {
423 snprintf(path, sizeof(path), "%s%s%s",
425 repodir[strlen(repodir) - 1] == '/' ? "" : "/",
427 if (access(path, F_OK) != 0)
429 if (read_conf_file(path, requested_repo,
444 config_init(const char *requested_repo)
448 const char *localbase;
450 char confpath[MAXPATHLEN];
451 struct config_value *cv;
454 for (i = 0; i < CONFIG_SIZE; i++) {
455 val = getenv(c[i].key);
459 case PKG_CONFIG_LIST:
460 /* Split up comma-separated items from env. */
461 c[i].list = malloc(sizeof(*c[i].list));
462 STAILQ_INIT(c[i].list);
463 for (env_list_item = strtok(val, ",");
464 env_list_item != NULL;
465 env_list_item = strtok(NULL, ",")) {
467 malloc(sizeof(struct config_value));
469 strdup(env_list_item);
470 STAILQ_INSERT_TAIL(c[i].list, cv,
481 /* Read LOCALBASE/etc/pkg.conf first. */
482 localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE;
483 snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf",
486 if (access(confpath, F_OK) == 0 && read_conf_file(confpath, NULL,
490 /* Then read in all repos from REPOS_DIR list of directories. */
491 if (c[REPOS_DIR].list == NULL) {
492 c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
493 STAILQ_INIT(c[REPOS_DIR].list);
494 cv = malloc(sizeof(struct config_value));
495 cv->value = strdup("/etc/pkg");
496 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
497 cv = malloc(sizeof(struct config_value));
498 if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
500 STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
503 STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
504 if (load_repositories(cv->value, requested_repo))
508 if (c[ABI].val == NULL && c[ABI].value == NULL) {
509 if (pkg_get_myabi(abi, BUFSIZ) != 0)
510 errx(EXIT_FAILURE, "Failed to determine the system "
515 subst_packagesite(c[ABI].value != NULL ? c[ABI].value : c[ABI].val);
521 config_string(pkg_config_key k, const char **val)
523 if (c[k].type != PKG_CONFIG_STRING)
526 if (c[k].value != NULL)
535 config_bool(pkg_config_key k, bool *val)
539 if (c[k].type != PKG_CONFIG_BOOL)
544 if (c[k].value != NULL)
549 if (boolstr_to_bool(value))
556 config_finish(void) {
559 for (i = 0; i < CONFIG_SIZE; i++)