Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 12 Dec 2013 17:59:09 +0000 (UTC)
From:      Bryan Drewery <bdrewery@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r259266 - head/usr.sbin/pkg
Message-ID:  <201312121759.rBCHx98F014632@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: bdrewery (ports committer)
Date: Thu Dec 12 17:59:09 2013
New Revision: 259266
URL: http://svnweb.freebsd.org/changeset/base/259266

Log:
  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

Modified:
  head/usr.sbin/pkg/config.c
  head/usr.sbin/pkg/config.h
  head/usr.sbin/pkg/pkg.7

Modified: head/usr.sbin/pkg/config.c
==============================================================================
--- head/usr.sbin/pkg/config.c	Thu Dec 12 17:48:33 2013	(r259265)
+++ head/usr.sbin/pkg/config.c	Thu Dec 12 17:59:09 2013	(r259266)
@@ -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_
 			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_
 			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
 	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);

Modified: head/usr.sbin/pkg/config.h
==============================================================================
--- head/usr.sbin/pkg/config.h	Thu Dec 12 17:48:33 2013	(r259265)
+++ head/usr.sbin/pkg/config.h	Thu Dec 12 17:59:09 2013	(r259266)
@@ -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 {

Modified: head/usr.sbin/pkg/pkg.7
==============================================================================
--- head/usr.sbin/pkg/pkg.7	Thu Dec 12 17:48:33 2013	(r259265)
+++ head/usr.sbin/pkg/pkg.7	Thu Dec 12 17:59:09 2013	(r259266)
@@ -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.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312121759.rBCHx98F014632>