Radish alpha
H
HardenedBSD Package Manager
Radicle
Git (anonymous pull)
Log in to clone via SSH
Allow plugin to get configuration through libpkg using same mecanism that pkg.conf
Baptiste Daroussin committed 13 years ago
commit f1da9ee700ae1afc2fdcb34fc55c0598f8abb6ba
parent 84edaaacbab6df9f90d5197e9d88e56323b125fb
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