Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Allow to pipe events in json format though a unix socket/fifo
Baptiste Daroussin committed 13 years ago
commit 58d976e2c072a438e21b9fecac7e6e226c373ac0
parent 8128d5b
3 files changed +327 -1
modified libpkg/pkg_config.c
@@ -26,8 +26,11 @@
 */

#include <assert.h>
+
#include <sys/socket.h>
+
#include <sys/un.h>
#include <ctype.h>
#include <dlfcn.h>
+
#include <fcntl.h>
#include <err.h>
#include <errno.h>
#include <stdlib.h>
@@ -43,6 +46,7 @@
#define ABI_VAR_STRING "${ABI}"

pthread_mutex_t mirror_mtx;
+
int eventpipe = -1;

struct config_entry {
	uint8_t type;
@@ -213,6 +217,11 @@ static struct config_entry c[] = {
		"NAMESERVER",
		NULL,
	},
+
	[PKG_CONFIG_EVENT_PIPE] = {
+
		PKG_CONFIG_STRING,
+
		"EVENT_PIPE",
+
		NULL,
+
	}
};

static bool parsed = false;
@@ -221,6 +230,51 @@ static size_t c_size = sizeof(c) / sizeof(struct config_entry);
static void pkg_config_kv_free(struct pkg_config_kv *);

static void
+
connect_evpipe(const char *evpipe) {
+
	struct stat st;
+
	struct sockaddr_un sock;
+
	int flag = O_WRONLY;
+

+
	if (stat(evpipe, &st) != 0) {
+
		pkg_emit_error("No such event pipe: %s", evpipe);
+
		return;
+
	}
+

+
	if (!S_ISFIFO(st.st_mode) && !S_ISSOCK(st.st_mode)) {
+
		pkg_emit_error("%s is not a fifo or socket", evpipe);
+
		return;
+
	}
+

+
	if (S_ISFIFO(st.st_mode)) {
+
		flag |= O_NONBLOCK;
+
		if ((eventpipe = open(evpipe, flag)) == -1)
+
			pkg_emit_errno("open event pipe", evpipe);
+
		return;
+
	}
+

+
	if (S_ISSOCK(st.st_mode)) {
+
		if ((eventpipe = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+
			pkg_emit_errno("Open event pipe", evpipe);
+
			return;
+
		}
+
		memset(&sock, 0, sizeof(struct sockaddr_un));
+
		sock.sun_family = AF_UNIX;
+
		if (strlcpy(sock.sun_path, evpipe, sizeof(sock.sun_path)) >=
+
		    sizeof(sock.sun_path)) {
+
			pkg_emit_error("Socket path too long: %s", evpipe);
+
			close(eventpipe);
+
			return;
+
		}
+

+
		if (connect(eventpipe, (struct sockaddr *)&sock, SUN_LEN(&sock)) == -1) {
+
			pkg_emit_errno("Connect event pipe", evpipe);
+
			return;
+
		}
+
	}
+

+
}
+

+
static void
parse_config_sequence(yaml_document_t *doc, yaml_node_t *seq, struct pkg_config *conf)
{
	yaml_node_item_t *item = seq->data.sequence.items.start;
@@ -572,6 +626,7 @@ pkg_init(const char *path)
	const char *errstr = NULL;
	const char *proxy = NULL;
	const char *nsname = NULL;
+
	const char *evpipe = NULL;
	struct pkg_config *conf;
	struct pkg_config_value *v;
	struct pkg_config_kv *kv;
@@ -742,6 +797,11 @@ pkg_init(const char *path)

	parsed = true;

+
	/* Start the event pipe */
+
	pkg_config_string(PKG_CONFIG_EVENT_PIPE, &evpipe);
+
	if (evpipe != NULL)
+
		connect_evpipe(evpipe);
+

	/* set the environement variable for libfetch for proxies if any */
	pkg_config_string(PKG_CONFIG_HTTP_PROXY, &proxy);
	if (proxy != NULL)
modified libpkg/pkg_event.c
@@ -1,5 +1,5 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * All rights reserved.
 * 
@@ -27,12 +27,276 @@

#include <syslog.h>

+
#define _WITH_DPRINTF
#include "pkg.h"
+
#include "private/pkg.h"
#include "private/event.h"

static pkg_event_cb _cb = NULL;
static void *_data = NULL;

+
static void
+
pipeevent(struct pkg_event *ev)
+
{
+
	struct pkg *pkg = NULL;
+
	struct pkg_dep *dep = NULL;
+
	struct sbuf *msg;
+
	const char *message;
+
	const char *name, *version, *newversion;
+

+
	if (eventpipe < 0)
+
		return;
+

+
	msg = sbuf_new_auto();
+

+
	switch(ev->type) {
+
	case PKG_EVENT_ERRNO:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR\", "
+
		    "\"data\": {\"msg\": \"%s(%s)\"}}",
+
		    ev->e_errno.func, ev->e_errno.arg);
+
		break;
+
	case PKG_EVENT_ERROR:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR\", "
+
		    "\"data\": {\"msg\": \"%s\"}}",
+
		    ev->e_pkg_error.msg);
+
		break;
+
	case PKG_EVENT_DEVELOPER_MODE:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR\", "
+
		    "\"msg\": \"DEVELOPPER_MODE: %s\"}",
+
		    ev->e_pkg_error.msg);
+
		break;
+
	case PKG_EVENT_FETCHING:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_FETCH\", "
+
		    "\"data\": { "
+
		    "\"url\": \"%s\", "
+
		    "\"fetched\": %" PRId64 ", "
+
		    "\"total\": %" PRId64
+
		    "}}",
+
		    ev->e_fetching.url,
+
		    ev->e_fetching.done,
+
		    ev->e_fetching.total
+
		    );
+
		break;
+
	case PKG_EVENT_INSTALL_BEGIN:
+
		pkg_get(ev->e_install_begin.pkg, PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_INSTALL_BEGIN\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version
+
		    );
+
		break;
+
	case PKG_EVENT_INSTALL_FINISHED:
+
		pkg_get(ev->e_install_finished.pkg,
+
		    PKG_MESSAGE, &message,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_INSTALL_FINISHED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\", "
+
		    "\"message\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version,
+
		    message
+
		    );
+
		break;
+
	case PKG_EVENT_INTEGRITYCHECK_BEGIN:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_INTEGRITYCHECK_BEGIN\", "
+
		    "\"data\": {"
+
		    "}}");
+
		break;
+
	case PKG_EVENT_INTEGRITYCHECK_FINISHED:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_INTEGRITYCHECK_FINISHED\", "
+
		    "\"data\": {"
+
		    "}}");
+
		break;
+
	case PKG_EVENT_DEINSTALL_BEGIN:
+
		pkg_get(ev->e_deinstall_begin.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_DEINSTALL_BEGIN\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version
+
		    );
+
		break;
+
	case PKG_EVENT_DEINSTALL_FINISHED:
+
		pkg_get(ev->e_deinstall_finished.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_DEINSTALL_FINISHED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version
+
		    );
+
		break;
+
	case PKG_EVENT_UPGRADE_BEGIN:
+
		pkg_get(ev->e_upgrade_begin.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version,
+
		    PKG_NEWVERSION, &newversion);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_UPGRADE_BEGIN\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\" ,"
+
		    "\"pkgnewversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version,
+
		    newversion
+
		    );
+
		break;
+
	case PKG_EVENT_UPGRADE_FINISHED:
+
		pkg_get(ev->e_upgrade_finished.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version,
+
		    PKG_NEWVERSION, &newversion);
+

+
		sbuf_printf(msg, "{ \"type\": \"INFO_UPGRADE_FINISHED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\" ,"
+
		    "\"pkgnewversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version,
+
		    newversion
+
		    );
+
		break;
+
	case PKG_EVENT_LOCKED:
+
		pkg_get(ev->e_locked.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_LOCKED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version
+
		    );
+
		break;
+
	case PKG_EVENT_REQUIRED:
+
		pkg_get(ev->e_required.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_REQUIRED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\", "
+
		    "\"force\": %s, "
+
		    "\"required_by\": [",
+
		    name,
+
		    version,
+
		    ev->e_required.force == 1 ? "true": "false");
+
		while (pkg_rdeps(pkg, &dep) == EPKG_OK)
+
			sbuf_printf(msg, "{ \"pkgname\": \"%s\", "
+
			    "\"pkgversion\": \"%s\" }, ",
+
			    pkg_dep_name(dep),
+
			    pkg_dep_version(dep));
+
		sbuf_setpos(msg, sbuf_len(msg) - 2);
+
		sbuf_cat(msg, "]}}");
+
		break;
+
	case PKG_EVENT_ALREADY_INSTALLED:
+
		pkg_get(ev->e_already_installed.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_ALREADY_INSTALLED\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version);
+
		break;
+
	case PKG_EVENT_MISSING_DEP:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_MISSING_DEP\", "
+
		    "\"data\": { "
+
		    "\"depname\": \"%s\", "
+
		    "\"depversion\": \"%s\""
+
		    "}}" ,
+
		    pkg_dep_name(ev->e_missing_dep.dep),
+
		    pkg_dep_version(ev->e_missing_dep.dep));
+
		break;
+
	case PKG_EVENT_NOREMOTEDB:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_NOREMOTEDB\", "
+
		    "\"data\": { "
+
		    "\"url\": \"%s\" "
+
		    "}}" ,
+
		    ev->e_remotedb.repo);
+
		break;
+
	case PKG_EVENT_NOLOCALDB:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_NOLOCALDB\", "
+
		    "\"data\": {} ");
+
		break;
+
	case PKG_EVENT_NEWPKGVERSION:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_NEWPKGVERSION\", "
+
		    "\"data\": {} ");
+
		break;
+
	case PKG_EVENT_FILE_MISMATCH:
+
		pkg_get(ev->e_file_mismatch.pkg,
+
		    PKG_NAME, &name,
+
		    PKG_VERSION, &version);
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_FILE_MISMATCH\", "
+
		    "\"data\": { "
+
		    "\"pkgname\": \"%s\", "
+
		    "\"pkgversion\": \"%s\", "
+
		    "\"path\": \"%s\""
+
		    "}}",
+
		    name,
+
		    version,
+
		    pkg_file_path(ev->e_file_mismatch.file));
+
		break;
+
	case PKG_EVENT_PLUGIN_ERRNO:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_PLUGIN\", "
+
		    "\"data\": {"
+
		    "\"plugin\": \"%s\", "
+
		    "\"msg\": \"%s(%s)\""
+
		    "}}",
+
		    pkg_plugin_get(ev->e_plugin_errno.plugin, PKG_PLUGIN_NAME),
+
		    ev->e_plugin_errno.func, ev->e_plugin_errno.arg);
+
		break;
+
	case PKG_EVENT_PLUGIN_ERROR:
+
		sbuf_printf(msg, "{ \"type\": \"ERROR_PLUGIN\", "
+
		    "\"data\": {"
+
		    "\"plugin\": \"%s\", "
+
		    "\"msg\": \"%s\""
+
		    "}}",
+
		    pkg_plugin_get(ev->e_plugin_error.plugin, PKG_PLUGIN_NAME),
+
		    ev->e_plugin_error.msg);
+
		break;
+
	case PKG_EVENT_PLUGIN_INFO:
+
		sbuf_printf(msg, "{ \"type\": \"INFO_PLUGIN\", "
+
		    "\"data\": {"
+
		    "\"plugin\": \"%s\", "
+
		    "\"msg\": \"%s\""
+
		    "}}",
+
		    pkg_plugin_get(ev->e_plugin_info.plugin, PKG_PLUGIN_NAME),
+
		    ev->e_plugin_info.msg);
+
		break;
+
	default:
+
		break;
+
	}
+
	sbuf_finish(msg);
+
	dprintf(eventpipe, "%s\n", sbuf_data(msg));
+
}
+

void
pkg_event_register(pkg_event_cb cb, void *data)
{
@@ -46,6 +310,7 @@ pkg_emit_event(struct pkg_event *ev)
	pkg_plugins_hook_run(PKG_PLUGIN_HOOK_EVENT, ev, NULL);
	if (_cb != NULL)
		_cb(_data, ev);
+
	pipeevent(ev);
}

void
modified libpkg/private/pkg.h
@@ -82,6 +82,7 @@
	} while (0)

extern pthread_mutex_t mirror_mtx;
+
extern int eventpipe;

struct pkg {
	struct sbuf	*fields[PKG_NUM_FIELDS];