Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Allow plugin to get configuration through libpkg using same mecanism that pkg.conf
Baptiste Daroussin committed 13 years ago
commit f1da9ee700ae1afc2fdcb34fc55c0598f8abb6ba
parent 84edaaa
4 files changed +459 -77
modified libpkg/pkg.h
@@ -63,7 +63,6 @@ struct pkg_jobs;
struct pkg_repos;
struct pkg_repos_entry;

-
struct pkg_config;
struct pkg_config_kv;
struct pkg_config_value;

@@ -268,6 +267,7 @@ typedef enum _pkg_config_key {
	PKG_CONFIG_ENABLE_PLUGINS,
	PKG_CONFIG_PLUGINS,
	PKG_CONFIG_DEBUG_SCRIPTS,
+
	PKG_CONFIG_PLUGINS_CONF_DIR,
} pkg_config_key;

typedef enum {
@@ -915,6 +915,20 @@ int pkg_plugin_set(struct pkg_plugin *p, pkg_plugin_key key, const char *str);
const char *pkg_plugin_get(struct pkg_plugin *p, pkg_plugin_key key);
void *pkg_plugin_func(struct pkg_plugin *p, const char *func);

+
int pkg_plugin_conf_add_string(struct pkg_plugin *p, uint8_t id, const char *key, const char *def);
+
int pkg_plugin_conf_add_bool(struct pkg_plugin *p, uint8_t id, const char *key, bool val);
+
int pkg_plugin_conf_add_integer(struct pkg_plugin *p, uint8_t id, const char *key, int64_t integer);
+
int pkg_plugin_conf_add_kvlist(struct pkg_plugin *p, uint8_t id, const char *key);
+
int pkg_plugin_conf_add_list(struct pkg_plugin *p, uint8_t id, const char *key);
+

+
int pkg_plugin_conf_string(struct pkg_plugin *p, uint8_t key, const char **value);
+
int pkg_plugin_conf_bool(struct pkg_plugin *p, uint8_t key, bool *value);
+
int pkg_plugin_conf_kvlist(struct pkg_plugin *p, uint8_t key, struct pkg_config_kv **kv);
+
int pkg_plugin_conf_list(struct pkg_plugin *p, uint8_t key, struct pkg_config_value **v);
+
int pkg_plugin_conf_integer(struct pkg_plugin *p, uint8_t key, int64_t *value);
+

+
int pkg_plugin_parse(struct pkg_plugin *p);
+

/**
 * This is where plugin hook into the library using pkg_plugin_hook()
 * @todo: Document
modified libpkg/pkg_config.c
@@ -40,163 +40,134 @@
#include "private/pkg.h"
#include "private/event.h"

-
#define STRING 0
-
#define BOOL 1
-
#define KVLIST 2
-
#define INTEGER 3
-
#define LIST 4
-

#define ABI_VAR_STRING "${ABI}"

-
struct pkg_config_kv {
-
	char *key;
-
	char *value;
-
	STAILQ_ENTRY(pkg_config_kv) next;
-
};
-

-
struct pkg_config_value {
-
	char *value;
-
	STAILQ_ENTRY(pkg_config_value) next;
-
};
-

struct config_entry {
	uint8_t type;
	const char *key;
	const char *def;
};

-
struct pkg_config {
-
	pkg_config_key id;
-
	uint8_t type;
-
	const char *key;
-
	const void *def;
-
	bool fromenv;
-
	union {
-
		char *string;
-
		uint64_t integer;
-
		bool boolean;
-
		STAILQ_HEAD(, pkg_config_kv) kvlist;
-
		STAILQ_HEAD(, pkg_config_value) list;
-
	};
-
	UT_hash_handle hh;
-
	UT_hash_handle hhkey;
-
};
-

static char myabi[BUFSIZ];
static struct pkg_config *config = NULL;
static struct pkg_config *config_by_key = NULL;

static struct config_entry c[] = {
	[PKG_CONFIG_REPO] = {
-
		STRING,
+
		CONF_STRING,
		"PACKAGESITE",
		NULL,
	},
	[PKG_CONFIG_DBDIR] = {
-
		STRING,
+
		CONF_STRING,
		"PKG_DBDIR",
		"/var/db/pkg",
	},
	[PKG_CONFIG_CACHEDIR] = {
-
		STRING,
+
		CONF_STRING,
		"PKG_CACHEDIR",
		"/var/cache/pkg",
	},
	[PKG_CONFIG_PORTSDIR] = {
-
		STRING,
+
		CONF_STRING,
		"PORTSDIR",
		"/usr/ports",
	},
	[PKG_CONFIG_REPOKEY] = {
-
		STRING,
+
		CONF_STRING,
		"PUBKEY",
		NULL,
	},
	[PKG_CONFIG_MULTIREPOS] = {
-
		BOOL,
+
		CONF_BOOL,
		"PKG_MULTIREPOS",
		NULL,
	},
	[PKG_CONFIG_HANDLE_RC_SCRIPTS] = {
-
		BOOL,
+
		CONF_BOOL,
		"HANDLE_RC_SCRIPTS",
		NULL,
	},
	[PKG_CONFIG_ASSUME_ALWAYS_YES] = {
-
		BOOL,
+
		CONF_BOOL,
		"ASSUME_ALWAYS_YES",
		NULL,
	},
	[PKG_CONFIG_REPOS] = {
-
		KVLIST,
+
		CONF_KVLIST,
		"REPOS",
		"NULL",
	},
	[PKG_CONFIG_PLIST_KEYWORDS_DIR] = {
-
		STRING,
+
		CONF_STRING,
		"PLIST_KEYWORDS_DIR",
		NULL,
	},
	[PKG_CONFIG_SYSLOG] = {
-
		BOOL,
+
		CONF_BOOL,
		"SYSLOG",
		"YES",
	},
	[PKG_CONFIG_SHLIBS] = {
-
		BOOL,
+
		CONF_BOOL,
		"SHLIBS",
		"NO",
	},
	[PKG_CONFIG_AUTODEPS] = {
-
		BOOL,
+
		CONF_BOOL,
		"AUTODEPS",
		"NO",
	},
	[PKG_CONFIG_ABI] = {
-
		STRING,
+
		CONF_STRING,
		"ABI",
		myabi,
	},
	[PKG_CONFIG_DEVELOPER_MODE] = {
-
		BOOL,
+
		CONF_BOOL,
		"DEVELOPER_MODE",
		"NO",
	},
	[PKG_CONFIG_PORTAUDIT_SITE] = {
-
		STRING,
+
		CONF_STRING,
		"PORTAUDIT_SITE",
		"http://portaudit.FreeBSD.org/auditfile.tbz",
	},
	[PKG_CONFIG_SRV_MIRROR] = {
-
		BOOL,
+
		CONF_BOOL,
		"SRV_MIRRORS",
		"YES",
	},
	[PKG_CONFIG_FETCH_RETRY] = {
-
		INTEGER,
+
		CONF_INTEGER,
		"FETCH_RETRY",
		"3",
	},
	[PKG_CONFIG_PLUGINS_DIR] = {
-
		STRING,
+
		CONF_STRING,
		"PKG_PLUGINS_DIR",
		PREFIX"/lib/pkg/",
	},
	[PKG_CONFIG_ENABLE_PLUGINS] = {
-
		BOOL,
+
		CONF_BOOL,
		"PKG_ENABLE_PLUGINS",
		"YES",
	},
	[PKG_CONFIG_PLUGINS] = {
-
		LIST,
+
		CONF_LIST,
		"PLUGINS",
		"NULL",
	},
	[PKG_CONFIG_DEBUG_SCRIPTS] = {
-
		BOOL,
+
		CONF_BOOL,
		"DEBUG_SCRIPTS",
		"NO",
	},
+
	[PKG_CONFIG_PLUGINS_CONF_DIR] = {
+
		CONF_STRING,
+
		"PLUGINS_CONF_DIR",
+
		PREFIX"/etc/pkg/",
+
	},
};

static bool parsed = false;
@@ -245,8 +216,8 @@ parse_config_mapping(yaml_document_t *doc, yaml_node_t *map, struct pkg_config *
	}
}

-
static void
-
parse_configuration(yaml_document_t *doc, yaml_node_t *node)
+
void
+
pkg_config_parse(yaml_document_t *doc, yaml_node_t *node, struct pkg_config *conf_by_key)
{
	struct pkg_config *conf;
	yaml_node_pair_t *pair;
@@ -282,10 +253,10 @@ parse_configuration(yaml_document_t *doc, yaml_node_t *node)
			sbuf_putc(b, toupper(key->data.scalar.value[i]));

		sbuf_finish(b);
-
		HASH_FIND(hhkey, config_by_key, sbuf_data(b), sbuf_len(b), conf);
+
		HASH_FIND(hhkey, conf_by_key, sbuf_data(b), sbuf_len(b), conf);
		if (conf != NULL) {
			switch (conf->type) {
-
			case STRING:
+
			case CONF_STRING:
				if (val->type != YAML_SCALAR_NODE) {
					pkg_emit_error("Expecting a string for key %s,"
					    " ignoring...", key->data.scalar.value);
@@ -296,7 +267,7 @@ parse_configuration(yaml_document_t *doc, yaml_node_t *node)
					conf->string = strdup(val->data.scalar.value);
				}
				break;
-
			case INTEGER:
+
			case CONF_INTEGER:
				if (val->type != YAML_SCALAR_NODE) {
					pkg_emit_error("Expecting an integer for key %s,"
					    " ignoring...", key->data.scalar.value);
@@ -311,7 +282,7 @@ parse_configuration(yaml_document_t *doc, yaml_node_t *node)
					conf->integer = newint;
				}
				break;
-
			case BOOL:
+
			case CONF_BOOL:
				if (val->type != YAML_SCALAR_NODE) {
					pkg_emit_error("Expecting an integer for key %s,"
					    " ignoring...", key->data.scalar.value);
@@ -329,14 +300,14 @@ parse_configuration(yaml_document_t *doc, yaml_node_t *node)
					}
				}
				break;
-
			case KVLIST:
+
			case CONF_KVLIST:
				if (val->type != YAML_MAPPING_NODE) {
					pkg_emit_error("Expecting a key/value list for key %s,"
					    " ignoring...", key->data.scalar.value);
				}
				parse_config_mapping(doc, val, conf);
				break;
-
			case LIST:
+
			case CONF_LIST:
				if (val->type != YAML_SEQUENCE_NODE) {
					pkg_emit_error("Expecting a string list for key %s,"
					    " ignoring...", key->data.scalar.value);
@@ -462,7 +433,7 @@ pkg_config_kvlist(pkg_config_key key, struct pkg_config_kv **kv)
	if (conf == NULL)
		return (EPKG_FATAL);

-
	if (conf->type != KVLIST) {
+
	if (conf->type != CONF_KVLIST) {
		pkg_emit_error("this config entry is not a \"key: value\" list");
		return (EPKG_FATAL);
	}
@@ -492,7 +463,7 @@ pkg_config_list(pkg_config_key key, struct pkg_config_value **v)
	if (conf == NULL)
		return (EPKG_FATAL);

-
	if (conf->type != LIST) {
+
	if (conf->type != CONF_LIST) {
		pkg_emit_error("this config entry is not a list");
		return (EPKG_FATAL);
	}
@@ -505,7 +476,7 @@ pkg_config_list(pkg_config_key key, struct pkg_config_value **v)
		return (EPKG_END);
	else
		return (EPKG_OK);
-
};
+
}

const char *
pkg_config_value(struct pkg_config_value *v)
@@ -559,7 +530,7 @@ pkg_init(const char *path)
		val = getenv(c[i].key);

		switch (c[i].type) {
-
		case STRING:
+
		case CONF_STRING:
			if (val != NULL) {
				conf->string = strdup(val);
				conf->fromenv = true;
@@ -569,7 +540,7 @@ pkg_init(const char *path)
			else
				conf->string = NULL;
			break;
-
		case INTEGER:
+
		case CONF_INTEGER:
			if (val == NULL)
				val = c[i].def;
			else
@@ -581,7 +552,7 @@ pkg_init(const char *path)
				return (EPKG_FATAL);
			}
			break;
-
		case BOOL:
+
		case CONF_BOOL:
			if (val == NULL)
				val = c[i].def;
			else
@@ -596,10 +567,10 @@ pkg_init(const char *path)
				conf->boolean = false;
			}
			break;
-
		case KVLIST:
+
		case CONF_KVLIST:
			STAILQ_INIT(&conf->kvlist);
			break;
-
		case LIST:
+
		case CONF_LIST:
			STAILQ_INIT(&conf->list);
			break;
		}
@@ -631,7 +602,7 @@ pkg_init(const char *path)
		if (node->type != YAML_MAPPING_NODE) {
			pkg_emit_error("Invalid configuration format, ignoring the configuration file");
		} else {
-
			parse_configuration(&doc, node);
+
			pkg_config_parse(&doc, node, config);
		}
	} else {
		pkg_emit_error("Invalid configuration format, ignoring the configuration file");
@@ -654,9 +625,9 @@ pkg_config_free(struct pkg_config *conf)
	if (conf == NULL)
		return;

-
	if (conf->type == STRING)
+
	if (conf->type == CONF_STRING)
		free(conf->string);
-
	else if (conf->type == KVLIST) {
+
	else if (conf->type == CONF_KVLIST) {
		while (!STAILQ_EMPTY(&conf->kvlist)) {
			k = STAILQ_FIRST(&conf->kvlist);
			free(k->key);
@@ -664,7 +635,7 @@ pkg_config_free(struct pkg_config *conf)
			STAILQ_REMOVE_HEAD(&conf->kvlist, next);
			free(k);
		}
-
	} else if (conf->type == LIST) {
+
	} else if (conf->type == CONF_LIST) {
		while (!STAILQ_EMPTY(&conf->kvlist)) {
			v = STAILQ_FIRST(&conf->list);
			free(v->value);
modified libpkg/plugins.c
@@ -30,6 +30,8 @@
#include <sys/types.h>
#include <sys/stat.h>

+
#include <ctype.h>
+
#include <errno.h>
#include <fts.h>
#include <fcntl.h>
#include <dlfcn.h>
@@ -54,7 +56,10 @@ struct plugin_hook {
struct pkg_plugin {
	struct sbuf *fields[PLUGIN_NUMFIELDS];
	void *lh;						/* library handle */
+
	bool parsed;
	struct plugin_hook *hooks;
+
	struct pkg_config *conf;
+
	struct pkg_config *conf_by_key;
	STAILQ_ENTRY(pkg_plugin) next;
};

@@ -166,6 +171,196 @@ pkg_plugin_get(struct pkg_plugin *p, pkg_plugin_key key)
}

int
+
pkg_plugin_conf_add_string(struct pkg_plugin *p, uint8_t id, const char *key, const char *def)
+
{
+
	struct pkg_config *conf;
+
	char *val;
+

+
	HASH_FIND_INT(p->conf, &id, conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same id is already registred");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND(hhkey, p->conf_by_key, __DECONST(char *, key), strlen(key), conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same key(%s) is already registred", key);
+
		return (EPKG_FATAL);
+
	}
+

+
	conf = malloc(sizeof(struct pkg_config));
+
	conf->id = id;
+
	conf->key = key;
+
	conf->type = CONF_STRING;
+
	conf->fromenv = false;
+
	val = getenv(key);
+
	if (val != NULL) {
+
		conf->string = strdup(val);
+
		conf->fromenv = true;
+
	} else if (def != NULL) {
+
		conf->string = strdup(def);
+
	} else {
+
		conf->string = NULL;
+
	}
+

+
	HASH_ADD_INT(p->conf, id, conf);
+
	HASH_ADD_KEYPTR(hhkey, p->conf_by_key, __DECONST(char *, conf->key),
+
	    strlen(conf->key), conf);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_add_bool(struct pkg_plugin *p, uint8_t id, const char *key, bool boolean)
+
{
+
	struct pkg_config *conf;
+
	char *val;
+

+
	HASH_FIND_INT(p->conf, &id, conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same id is already registred");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND(hhkey, p->conf_by_key, __DECONST(char *, key), strlen(key), conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same key(%s) is already registred", key);
+
		return (EPKG_FATAL);
+
	}
+

+
	conf = malloc(sizeof(struct pkg_config));
+
	conf->id = id;
+
	conf->key = key;
+
	conf->type = CONF_STRING;
+
	conf->fromenv = false;
+
	val = getenv(key);
+
	if (val != NULL) {
+
		conf->fromenv = true;
+
		if (val != NULL && (
+
		    strcmp(val, "1") == 0 ||
+
		    strcasecmp(val, "yes") == 0 ||
+
		    strcasecmp(val, "true") == 0 ||
+
		    strcasecmp(val, "on") == 0)) {
+
			conf->boolean = true;
+
		} else {
+
			conf->boolean = false;
+
		}
+
	} else {
+
		conf->boolean = boolean;
+
	}
+

+
	HASH_ADD_INT(p->conf, id, conf);
+
	HASH_ADD_KEYPTR(hhkey, p->conf_by_key, __DECONST(char *, conf->key),
+
	    strlen(conf->key), conf);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_add_integer(struct pkg_plugin *p, uint8_t id, const char *key, int64_t integer)
+
{
+
	struct pkg_config *conf;
+
	const char *errstr;
+
	char *val;
+

+
	HASH_FIND_INT(p->conf, &id, conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same id is already registred");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND(hhkey, p->conf_by_key, __DECONST(char *, key), strlen(key), conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same key(%s) is already registred", key);
+
		return (EPKG_FATAL);
+
	}
+

+
	conf = malloc(sizeof(struct pkg_config));
+
	conf->id = id;
+
	conf->key = key;
+
	conf->type = CONF_STRING;
+
	conf->fromenv = false;
+
	val = getenv(key);
+
	if (val != NULL) {
+
		conf->fromenv = true;
+
		conf->integer = strtonum(val, 0, INT64_MAX, &errstr);
+
		if (errstr != NULL) {
+
			pkg_emit_error("Unable to convert %s to int64: %s",
+
			    val, errstr);
+
			return (EPKG_FATAL);
+
		}
+
	} else {
+
		conf->integer = integer;
+
	}
+

+
	HASH_ADD_INT(p->conf, id, conf);
+
	HASH_ADD_KEYPTR(hhkey, p->conf_by_key, __DECONST(char *, conf->key),
+
	    strlen(conf->key), conf);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_add_kvlist(struct pkg_plugin *p, uint8_t id, const char *key)
+
{
+
	struct pkg_config *conf;
+

+
	HASH_FIND_INT(p->conf, &id, conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same id is already registred");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND(hhkey, p->conf_by_key, __DECONST(char *, key), strlen(key), conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same key(%s) is already registred", key);
+
		return (EPKG_FATAL);
+
	}
+

+
	conf = malloc(sizeof(struct pkg_config));
+
	conf->id = id;
+
	conf->key = key;
+
	conf->type = CONF_KVLIST;
+
	STAILQ_INIT(&conf->kvlist);
+

+
	HASH_ADD_INT(p->conf, id, conf);
+
	HASH_ADD_KEYPTR(hhkey, p->conf_by_key, __DECONST(char *, conf->key),
+
	    strlen(conf->key), conf);
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_add_list(struct pkg_plugin *p, uint8_t id, const char *key)
+
{
+
	struct pkg_config *conf;
+

+
	HASH_FIND_INT(p->conf, &id, conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same id is already registred");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND(hhkey, p->conf_by_key, __DECONST(char *, key), strlen(key), conf);
+
	if (conf != NULL) {
+
		pkg_emit_error("A configuration with the same key(%s) is already registred", key);
+
		return (EPKG_FATAL);
+
	}
+

+
	conf = malloc(sizeof(struct pkg_config));
+
	conf->id = id;
+
	conf->key = key;
+
	conf->type = CONF_LIST;
+
	STAILQ_INIT(&conf->list);
+

+
	HASH_ADD_INT(p->conf, id, conf);
+
	HASH_ADD_KEYPTR(hhkey, p->conf_by_key, __DECONST(char *, conf->key),
+
	    strlen(conf->key), conf);
+

+
	return (EPKG_OK);
+
}
+

+
int
pkg_plugins(struct pkg_plugin **plugin)
{
	assert(&ph != NULL);
@@ -226,6 +421,170 @@ pkg_plugins_init(void)
}

int
+
pkg_plugin_conf_string(struct pkg_plugin *p, uint8_t key, const char **val)
+
{
+
	struct pkg_config *conf;
+

+
	if (p->parsed != true) {
+
		pkg_emit_error("configuration file not parsed");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND_INT(p->conf, &key, conf);
+
	if (conf == NULL)
+
		*val = NULL;
+
	else
+
		*val = conf->string;
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_integer(struct pkg_plugin *p, uint8_t key, int64_t *val)
+
{
+
	struct pkg_config *conf;
+

+
	if (p->parsed != true) {
+
		pkg_emit_error("configuration file not parsed");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND_INT(p->conf, &key, conf);
+
	if (conf == NULL)
+
		return (EPKG_FATAL);
+

+
	*val = conf->integer;
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_bool(struct pkg_plugin *p, uint8_t key, bool *val)
+
{
+
	struct pkg_config *conf;
+

+
	if (p->parsed != true) {
+
		pkg_emit_error("configuration file not parsed");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND_INT(p->conf, &key, conf);
+
	if (conf == NULL)
+
		return (EPKG_FATAL);
+

+
	*val = conf->boolean;
+

+
	return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_kvlist(struct pkg_plugin *p, uint8_t key, struct pkg_config_kv **kv)
+
{
+
	struct pkg_config *conf;
+

+
	if (p->parsed != true) {
+
		pkg_emit_error("configuration file not parsed");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND_INT(p->conf, &key, conf);
+
	if (conf == NULL)
+
		return (EPKG_FATAL);
+

+
	if (conf->type != CONF_KVLIST) {
+
		pkg_emit_error("this config entry is not a \"key: value\" list");
+
		return (EPKG_FATAL);
+
	}
+

+
	if (*kv == NULL)
+
		*kv = STAILQ_FIRST(&(conf->kvlist));
+
	else
+
		*kv = STAILQ_NEXT(*kv, next);
+

+
	if (*kv == NULL)
+
		return (EPKG_END);
+
	else
+
		return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_conf_list(struct pkg_plugin *p, uint8_t key, struct pkg_config_value **v)
+
{
+
	struct pkg_config *conf;
+

+
	if (p->parsed != true) {
+
		pkg_emit_error("configuration file not parsed");
+
		return (EPKG_FATAL);
+
	}
+

+
	HASH_FIND_INT(p->conf, &key, conf);
+
	if (conf == NULL)
+
		return (EPKG_FATAL);
+

+
	if (conf->type != CONF_LIST) {
+
		pkg_emit_error("this config entry is not a list");
+
		return (EPKG_FATAL);
+
	}
+

+
	if (*v == NULL)
+
		*v = STAILQ_FIRST(&conf->list);
+
	else
+
		*v = STAILQ_NEXT(*v, next);
+
	if (*v == NULL)
+
		return (EPKG_END);
+
	else
+
		return (EPKG_OK);
+
}
+

+
int
+
pkg_plugin_parse(struct pkg_plugin *p)
+
{
+
	char confpath[MAXPATHLEN];
+
	const char *path;
+
	const char *plugname;
+
	FILE *fp;
+

+
	yaml_parser_t parser;
+
	yaml_document_t doc;
+
	yaml_node_t *node;
+

+
	pkg_config_string(PKG_CONFIG_PLUGINS_DIR, &path);
+
	plugname = pkg_plugin_get(p, PKG_PLUGIN_NAME);
+

+
	snprintf(confpath, sizeof(confpath), "%s/%s.conf", path, plugname);
+

+
	if ((fp = fopen(confpath, "r")) == NULL) {
+
		if (errno != ENOENT) {
+
			pkg_emit_errno("fopen", confpath);
+
			return (EPKG_FATAL);
+
		}
+
		p->parsed = true;
+
		return (EPKG_OK);
+
	}
+

+
	yaml_parser_initialize(&parser);
+
	yaml_parser_set_input_file(&parser, fp);
+
	yaml_parser_load(&parser, &doc);
+

+
	node = yaml_document_get_root_node(&doc);
+
	if (node != NULL) {
+
		if (node->type != YAML_MAPPING_NODE) {
+
			pkg_emit_error("Invalid configuration format, ignoring the configuration file");
+
		} else {
+
			pkg_config_parse(&doc, node, p->conf_by_key);
+
		}
+
	} else {
+
		pkg_emit_error("Invalid configuration format, ignoring the configuration file");
+
	}
+

+
	yaml_document_delete(&doc);
+
	yaml_parser_delete(&parser);
+

+
	p->parsed = true;
+
	return (EPKG_OK);
+
}
+

+
int
pkg_plugins_shutdown(void)
{
	struct pkg_plugin *p = NULL;
modified libpkg/private/pkg.h
@@ -39,6 +39,7 @@
#include <stdbool.h>
#include <uthash.h>

+
#include <yaml.h>
#include "private/utils.h"

#define PKG_NUM_FIELDS 18
@@ -159,6 +160,14 @@ typedef enum _pkg_job_flags {
	PKG_JOB_FLAGS_DRY_RUN =	(1 << 1),
} pkg_job_flags;

+
enum {
+
	CONF_STRING=0,
+
	CONF_BOOL,
+
	CONF_KVLIST,
+
	CONF_INTEGER,
+
	CONF_LIST
+
};
+

struct pkg_jobs_node {
	struct pkg	*pkg;
	size_t		 nrefs;
@@ -185,6 +194,33 @@ struct pkg_shlib {
	UT_hash_handle	hh;
};

+
struct pkg_config {
+
	uint8_t id;
+
	uint8_t type;
+
	const char *key;
+
	const void *def;
+
	bool fromenv;
+
	union {
+
		char *string;
+
		uint64_t integer;
+
		bool boolean;
+
		STAILQ_HEAD(, pkg_config_kv) kvlist;
+
		STAILQ_HEAD(, pkg_config_value) list;
+
	};
+
	UT_hash_handle hh;
+
	UT_hash_handle hhkey;
+
};
+

+
struct pkg_config_kv {
+
	char *key;
+
	char *value;
+
	STAILQ_ENTRY(pkg_config_kv) next;
+
};
+

+
struct pkg_config_value {
+
	char *value;
+
	STAILQ_ENTRY(pkg_config_value) next;
+
};

/* sql helpers */

@@ -314,4 +350,6 @@ int pkgdb_register_finale(struct pkgdb *db, int retcode);

int pkg_register_shlibs(struct pkg *pkg);

+
void pkg_config_parse(yaml_document_t *doc, yaml_node_t *node, struct pkg_config *conf_by_key);
+

#endif