Fix multi-repository support by properly respecting 'enabled' flag.
This will read the REPOS_DIR env/config setting (default is /etc/pkg and /usr/local/etc/pkg/repos) and use the last enabled repository. This can be changed in the environment using a comma-separated list, or in /usr/local/etc/pkg.conf with JSON array syntax of: REPOS_DIR: ["/etc/pkg", "/usr/local/etc/pkg/repos"] Approved by: bapt MFC after: 1 week
This commit is contained in:
parent
369f2ddcb8
commit
eb31a57474
@ -32,8 +32,10 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/elf_common.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <yaml.h>
|
||||
#include <ctype.h>
|
||||
#include <err.h>
|
||||
@ -51,11 +53,17 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#define roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
|
||||
|
||||
struct config_value {
|
||||
char *value;
|
||||
STAILQ_ENTRY(config_value) next;
|
||||
};
|
||||
|
||||
struct config_entry {
|
||||
uint8_t type;
|
||||
const char *key;
|
||||
const char *val;
|
||||
char *value;
|
||||
STAILQ_HEAD(, config_value) *list;
|
||||
bool envset;
|
||||
};
|
||||
|
||||
@ -65,6 +73,7 @@ static struct config_entry c[] = {
|
||||
"PACKAGESITE",
|
||||
URL_SCHEME_PREFIX "http://pkg.FreeBSD.org/${ABI}/latest",
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[ABI] = {
|
||||
@ -72,6 +81,7 @@ static struct config_entry c[] = {
|
||||
"ABI",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[MIRROR_TYPE] = {
|
||||
@ -79,6 +89,7 @@ static struct config_entry c[] = {
|
||||
"MIRROR_TYPE",
|
||||
"SRV",
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[ASSUME_ALWAYS_YES] = {
|
||||
@ -86,6 +97,7 @@ static struct config_entry c[] = {
|
||||
"ASSUME_ALWAYS_YES",
|
||||
"NO",
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[SIGNATURE_TYPE] = {
|
||||
@ -93,6 +105,7 @@ static struct config_entry c[] = {
|
||||
"SIGNATURE_TYPE",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[FINGERPRINTS] = {
|
||||
@ -100,6 +113,15 @@ static struct config_entry c[] = {
|
||||
"FINGERPRINTS",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
[REPOS_DIR] = {
|
||||
PKG_CONFIG_LIST,
|
||||
"REPOS_DIR",
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
false,
|
||||
},
|
||||
};
|
||||
@ -474,17 +496,34 @@ subst_packagesite(const char *abi)
|
||||
c[PACKAGESITE].value = strdup(sbuf_data(newval));
|
||||
}
|
||||
|
||||
static int
|
||||
boolstr_to_bool(const char *str)
|
||||
{
|
||||
if (str != NULL && (strcasecmp(str, "true") == 0 ||
|
||||
strcasecmp(str, "yes") == 0 || strcasecmp(str, "on") == 0 ||
|
||||
str[0] == '1'))
|
||||
return (true);
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
static void
|
||||
config_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype)
|
||||
{
|
||||
yaml_node_item_t *item;
|
||||
yaml_node_pair_t *pair;
|
||||
yaml_node_t *key, *val;
|
||||
yaml_node_t *key, *val, *item_val;
|
||||
struct sbuf *buf = sbuf_new_auto();
|
||||
struct config_entry *temp_config;
|
||||
struct config_value *cv;
|
||||
int i;
|
||||
size_t j;
|
||||
|
||||
pair = node->data.mapping.pairs.start;
|
||||
|
||||
/* Temporary config for configs that may be disabled. */
|
||||
temp_config = calloc(CONFIG_SIZE, sizeof(struct config_entry));
|
||||
|
||||
while (pair < node->data.mapping.pairs.top) {
|
||||
key = yaml_document_get_node(doc, pair->key);
|
||||
val = yaml_document_get_node(doc, pair->value);
|
||||
@ -530,7 +569,12 @@ config_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype)
|
||||
else if (strcasecmp(key->data.scalar.value,
|
||||
"fingerprints") == 0)
|
||||
sbuf_cpy(buf, "FINGERPRINTS");
|
||||
else { /* Skip unknown entries for future use. */
|
||||
else if (strcasecmp(key->data.scalar.value,
|
||||
"enabled") == 0) {
|
||||
/* Skip disabled repos. */
|
||||
if (!boolstr_to_bool(val->data.scalar.value))
|
||||
goto cleanup;
|
||||
} else { /* Skip unknown entries for future use. */
|
||||
++pair;
|
||||
continue;
|
||||
}
|
||||
@ -554,10 +598,58 @@ config_parse(yaml_document_t *doc, yaml_node_t *node, pkg_conf_file_t conftype)
|
||||
continue;
|
||||
}
|
||||
|
||||
c[i].value = strdup(val->data.scalar.value);
|
||||
/* Parse sequence value ["item1", "item2"] */
|
||||
switch (c[i].type) {
|
||||
case PKG_CONFIG_LIST:
|
||||
if (val->type != YAML_SEQUENCE_NODE) {
|
||||
fprintf(stderr, "Skipping invalid array "
|
||||
"value for %s.\n", c[i].key);
|
||||
++pair;
|
||||
continue;
|
||||
}
|
||||
item = val->data.sequence.items.start;
|
||||
temp_config[i].list =
|
||||
malloc(sizeof(*temp_config[i].list));
|
||||
STAILQ_INIT(temp_config[i].list);
|
||||
|
||||
while (item < val->data.sequence.items.top) {
|
||||
item_val = yaml_document_get_node(doc, *item);
|
||||
if (item_val->type != YAML_SCALAR_NODE) {
|
||||
++item;
|
||||
continue;
|
||||
}
|
||||
cv = malloc(sizeof(struct config_value));
|
||||
cv->value =
|
||||
strdup(item_val->data.scalar.value);
|
||||
STAILQ_INSERT_TAIL(temp_config[i].list, cv,
|
||||
next);
|
||||
++item;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Normal string value. */
|
||||
temp_config[i].value = strdup(val->data.scalar.value);
|
||||
break;
|
||||
}
|
||||
++pair;
|
||||
}
|
||||
|
||||
/* Repo is enabled, copy over all settings from temp_config. */
|
||||
for (i = 0; i < CONFIG_SIZE; i++) {
|
||||
if (c[i].envset)
|
||||
continue;
|
||||
switch (c[i].type) {
|
||||
case PKG_CONFIG_LIST:
|
||||
c[i].list = temp_config[i].list;
|
||||
break;
|
||||
default:
|
||||
c[i].value = temp_config[i].value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(temp_config);
|
||||
sbuf_delete(buf);
|
||||
}
|
||||
|
||||
@ -632,23 +724,84 @@ read_conf_file(const char *confpath, pkg_conf_file_t conftype)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
load_repositories(const char *repodir)
|
||||
{
|
||||
struct dirent *ent;
|
||||
DIR *d;
|
||||
char *p;
|
||||
size_t n;
|
||||
char path[MAXPATHLEN];
|
||||
int ret;
|
||||
|
||||
ret = 0;
|
||||
|
||||
if ((d = opendir(repodir)) == NULL)
|
||||
return (1);
|
||||
|
||||
while ((ent = readdir(d))) {
|
||||
/* Trim out 'repos'. */
|
||||
if ((n = strlen(ent->d_name)) <= 5)
|
||||
continue;
|
||||
p = &ent->d_name[n - 5];
|
||||
if (strcmp(p, ".conf") == 0) {
|
||||
snprintf(path, sizeof(path), "%s%s%s",
|
||||
repodir,
|
||||
repodir[strlen(repodir) - 1] == '/' ? "" : "/",
|
||||
ent->d_name);
|
||||
if (access(path, F_OK) == 0 &&
|
||||
read_conf_file(path, CONFFILE_REPO)) {
|
||||
ret = 1;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
closedir(d);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
int
|
||||
config_init(void)
|
||||
{
|
||||
const char *val;
|
||||
char *val;
|
||||
int i;
|
||||
const char *localbase;
|
||||
char *env_list_item;
|
||||
char confpath[MAXPATHLEN];
|
||||
struct config_value *cv;
|
||||
char abi[BUFSIZ];
|
||||
|
||||
for (i = 0; i < CONFIG_SIZE; i++) {
|
||||
val = getenv(c[i].key);
|
||||
if (val != NULL) {
|
||||
c[i].val = val;
|
||||
c[i].envset = true;
|
||||
switch (c[i].type) {
|
||||
case PKG_CONFIG_LIST:
|
||||
/* Split up comma-separated items from env. */
|
||||
c[i].list = malloc(sizeof(*c[i].list));
|
||||
STAILQ_INIT(c[i].list);
|
||||
for (env_list_item = strtok(val, ",");
|
||||
env_list_item != NULL;
|
||||
env_list_item = strtok(NULL, ",")) {
|
||||
cv =
|
||||
malloc(sizeof(struct config_value));
|
||||
cv->value =
|
||||
strdup(env_list_item);
|
||||
STAILQ_INSERT_TAIL(c[i].list, cv,
|
||||
next);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
c[i].val = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Read LOCALBASE/etc/pkg.conf first. */
|
||||
localbase = getenv("LOCALBASE") ? getenv("LOCALBASE") : _LOCALBASE;
|
||||
snprintf(confpath, sizeof(confpath), "%s/etc/pkg.conf",
|
||||
localbase);
|
||||
@ -657,10 +810,22 @@ config_init(void)
|
||||
CONFFILE_PKG))
|
||||
goto finalize;
|
||||
|
||||
snprintf(confpath, sizeof(confpath), "/etc/pkg/FreeBSD.conf");
|
||||
if (access(confpath, F_OK) == 0 && read_conf_file(confpath,
|
||||
CONFFILE_REPO))
|
||||
goto finalize;
|
||||
/* Then read in all repos from REPOS_DIR list of directories. */
|
||||
if (c[REPOS_DIR].list == NULL) {
|
||||
c[REPOS_DIR].list = malloc(sizeof(*c[REPOS_DIR].list));
|
||||
STAILQ_INIT(c[REPOS_DIR].list);
|
||||
cv = malloc(sizeof(struct config_value));
|
||||
cv->value = strdup("/etc/pkg");
|
||||
STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
|
||||
cv = malloc(sizeof(struct config_value));
|
||||
if (asprintf(&cv->value, "%s/etc/pkg/repos", localbase) < 0)
|
||||
goto finalize;
|
||||
STAILQ_INSERT_TAIL(c[REPOS_DIR].list, cv, next);
|
||||
}
|
||||
|
||||
STAILQ_FOREACH(cv, c[REPOS_DIR].list, next)
|
||||
if (load_repositories(cv->value))
|
||||
goto finalize;
|
||||
|
||||
finalize:
|
||||
if (c[ABI].val == NULL && c[ABI].value == NULL) {
|
||||
@ -704,10 +869,7 @@ config_bool(pkg_config_key k, bool *val)
|
||||
else
|
||||
value = c[k].val;
|
||||
|
||||
if (strcasecmp(value, "true") == 0 ||
|
||||
strcasecmp(value, "yes") == 0 ||
|
||||
strcasecmp(value, "on") == 0 ||
|
||||
*value == '1')
|
||||
if (boolstr_to_bool(value))
|
||||
*val = true;
|
||||
|
||||
return (0);
|
||||
|
@ -39,12 +39,14 @@ typedef enum {
|
||||
ASSUME_ALWAYS_YES,
|
||||
SIGNATURE_TYPE,
|
||||
FINGERPRINTS,
|
||||
REPOS_DIR,
|
||||
CONFIG_SIZE
|
||||
} pkg_config_key;
|
||||
|
||||
typedef enum {
|
||||
PKG_CONFIG_STRING=0,
|
||||
PKG_CONFIG_BOOL,
|
||||
PKG_CONFIG_LIST,
|
||||
} pkg_config_t;
|
||||
|
||||
typedef enum {
|
||||
|
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd November 19, 2013
|
||||
.Dd December 12, 2013
|
||||
.Dt PKG 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -152,6 +152,7 @@ MIRROR_TYPE: "srv",
|
||||
SIGNATURE_TYPE: "none",
|
||||
FINGERPRINTS: "/usr/share/keys/pkg",
|
||||
ASSUME_ALWAYS_YES: "yes"
|
||||
REPOS_DIR: ["/etc/pkg", "/usr/local/etc/pkg/repos"]
|
||||
.Ed
|
||||
.Pp
|
||||
Reference
|
||||
@ -194,14 +195,20 @@ The URL that
|
||||
.Xr pkg 8
|
||||
and other packages
|
||||
will be fetched from.
|
||||
.It Ev REPOS_DIR
|
||||
Comma-separated list of directories that should be searched for repository
|
||||
configuration files.
|
||||
.El
|
||||
.Sh FILES
|
||||
Configuration is read from the files in the listed order.
|
||||
The first enabled repository is the one used for bootstrapping
|
||||
This path can be changed by setting
|
||||
.Sy REPOS_DIR .
|
||||
The last enabled repository is the one used for bootstrapping
|
||||
.Xr pkg 8 .
|
||||
.Bl -tag -width "/usr/local/etc/pkg/repos/*.conf"
|
||||
.It Pa /usr/local/etc/pkg.conf
|
||||
.It Pa /etc/pkg/FreeBSD.conf
|
||||
.It Pa /usr/local/etc/pkg/repos/*.conf
|
||||
.El
|
||||
.Sh EXAMPLES
|
||||
Some examples are listed here.
|
||||
|
Loading…
Reference in New Issue
Block a user