summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2013-02-26 14:24:03 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2013-02-26 14:36:32 (GMT)
commit5b29f3ecc4e2edb172d50b23732a588b7a71ce62 (patch) (side-by-side diff)
tree79b94cbcd5b3a5456ad2a2b2c410886b7e1fb143 /src
parent1eeab02e9de4d54178279b347296e98fd97e2a00 (diff)
downloadwydawca-5b29f3ecc4e2edb172d50b23732a588b7a71ce62.tar.gz
wydawca-5b29f3ecc4e2edb172d50b23732a588b7a71ce62.tar.bz2
Introduce loadable modules.
* .gitignore: Update. * configure.ac: Require libtool Require Grecs tree-api. * Makefile.am: Incorporate libtool * bootstrap: Create m4 if it does not exist. * doc/Makefile.am: Use texi2html * grecs: Upgrade * src/module.c: New file. * src/Makefile.am (wydawca_SOURCES): Add module.c * src/config.c: Switch callbacks to tree-api. Add statements for working with modules: module-load-path, module-prepend-load-path and module in the global scope and module and module-config in notify-event blocks. * src/mail.c (do_notify): Call module_notify if a module is configured. * src/tcpwrap.c: Switch callbacks to tree-api. * src/wydawca.c (main): Load modules. * src/wydawca.h (notification) <modname> <modcfg,modnode>: New members. (module): New struct. (cb_module,modules_load,module_notify): New functions. (module_load_path) (module_prepend_load_path): New globals.
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am6
-rw-r--r--src/config.c201
-rw-r--r--src/mail.c5
-rw-r--r--src/module.c236
-rw-r--r--src/tcpwrap.c8
-rw-r--r--src/wydawca.c1
-rw-r--r--src/wydawca.h26
7 files changed, 401 insertions, 82 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2c8f3c4..d7241e9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,6 +35,7 @@ wydawca_SOURCES=\
job.c\
lock.c\
meta.c\
+ module.c\
net.c\
pidfile.c\
process.c\
@@ -67,12 +68,13 @@ SUFFIXES=.opt .c .h
incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = $(PP_SETUP_FILE)
-LDADD=../grecs/src/libgrecs.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@
+LDADD=../grecs/src/libgrecs.a @SQLLIB@ @GPGMELIB@ @MAILUTILS_LIBS@ @LIBLTDL@
AM_CPPFLAGS= \
-I$(top_srcdir)/grecs/src/ @MAILUTILS_INCLUDES@\
-DSYSCONFDIR=\"$(sysconfdir)\"\
-DLOCALSTATEDIR=\"$(localstatedir)\"\
+ -DWYDAWCA_MODDIR=\"$(WYDAWCA_MODDIR)\"\
-DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\
-DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"\
-DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)"
-
+AM_LDFLAGS=-export-dynamic
diff --git a/src/config.c b/src/config.c
index d6f6a89..b381834 100644
--- a/src/config.c
+++ b/src/config.c
@@ -230,10 +230,10 @@ assert_string_arg(grecs_locus_t *locus,
}
grecs_value_t *
-get_arg(grecs_locus_t *locus, grecs_value_t *value, unsigned n, int type)
+get_arg(grecs_value_t *value, unsigned n, int type)
{
- if (n >= value->v.arg.c) {
- grecs_error(locus, 0, _("not enough arguments"));
+ if (!value || value->type != GRECS_TYPE_ARRAY || n >= value->v.arg.c) {
+ grecs_error(&value->locus, 0, _("not enough arguments"));
return NULL;
}
value = value->v.arg.v[n];
@@ -246,12 +246,13 @@ get_arg(grecs_locus_t *locus, grecs_value_t *value, unsigned n, int type)
}
static int
-cb_mailer(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_mailer(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
int rc;
-
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
if (assert_string_arg(locus, cmd, value))
return 1;
rc = mu_mailer_create(&mailer, value->v.string);
@@ -264,12 +265,13 @@ cb_mailer(enum grecs_callback_command cmd,
}
static int
-cb_email_address(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_email_address(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
int rc = 1;
mu_address_t addr = NULL;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
struct grecs_list_entry *ep;
switch (value->type) {
@@ -315,13 +317,14 @@ cb_email_address(enum grecs_callback_command cmd,
}
static int
-cb_interval(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_interval(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
int rc;
time_t interval;
const char *endp;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
/* FIXME 1: Support arrays */
if (assert_string_arg(locus, cmd, value))
@@ -340,10 +343,12 @@ cb_interval(enum grecs_callback_command cmd,
static int
cb_absolute_name(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+ grecs_node_t *node,
+ void *varptr, void *cb_data)
{
char *word;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
/* FIXME 1: Support arrays */
if (assert_string_arg(locus, cmd, value))
@@ -360,11 +365,13 @@ cb_absolute_name(enum grecs_callback_command cmd,
static int
cb_set_umask(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+ grecs_node_t *node,
+ void *varptr, void *cb_data)
{
char *p;
mode_t m;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -474,20 +481,20 @@ parse_statmask(grecs_locus_t *loc, grecs_value_t *val, unsigned long *pmask)
}
static int
-cb_statistics(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_statistics(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
- return parse_statmask(locus, value, varptr);
+ return parse_statmask(&node->locus, node->v.value, varptr);
}
static int
-cb_sql_host(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_sql_host(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct sqlconn *pconn = varptr;
char *p;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -524,12 +531,13 @@ cb_sql_host(enum grecs_callback_command cmd,
}
static int
-cb_sql(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_sql(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct sqlconn *pconn;
void **pdata = cb_data;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
switch (cmd) {
case grecs_callback_section_begin:
@@ -586,10 +594,12 @@ static struct grecs_keyword sql_kw[] = {
};
static int
-cb_syslog_facility(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_syslog_facility(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -601,11 +611,12 @@ cb_syslog_facility(enum grecs_callback_command cmd,
}
static int
-cb_define_message(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_define_message(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
const char *ident;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (cmd != grecs_callback_set_value) {
grecs_error(locus, 0, _("Unexpected block statement"));
@@ -684,11 +695,12 @@ get_backup_version(grecs_locus_t *locus, const char *ctx, const char *version)
}
static int
-cb_backup(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_backup(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
enum backup_type *ptype = varptr;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -710,12 +722,13 @@ static struct grecs_keyword archive_kw[] = {
};
static int
-cb_archive(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_archive(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct archive_descr *arch = varptr;
void **pdata = cb_data;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
switch (cmd) {
case grecs_callback_section_begin:
@@ -783,11 +796,12 @@ static struct grecs_keyword mail_statistics_kw[] = {
};
static int
-cb_event(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_event(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
enum notification_event *pev = varptr;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -796,11 +810,12 @@ cb_event(enum grecs_callback_command cmd,
}
static int
-cb_recipient(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_recipient(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
enum notification_target *tgt = varptr;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -826,26 +841,34 @@ static struct grecs_keyword notify_event_kw[] = {
N_("Sign message with this key"),
grecs_type_string, GRECS_DFLT,
NULL, offsetof(struct notification, sign_keys) },
+ { "module", N_("name"),
+ N_("Name of the module to invoke on event"),
+ grecs_type_string, GRECS_DFLT,
+ NULL, offsetof(struct notification, modname) },
+ { "module-config", NULL,
+ N_("Module-specific configuration data"),
+ grecs_type_section, GRECS_INAC, NULL, 0, NULL, NULL, NULL },
{ NULL }
};
static int
-cb_notify_event(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_notify_event(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct notification *ntf;
void **pdata = cb_data;
+ grecs_locus_t *locus = &node->locus;
switch (cmd) {
case grecs_callback_section_begin:
ntf = grecs_zalloc(sizeof(*ntf));
+ ntf->modnode = grecs_find_node(node->down, "module-config");
*pdata = ntf;
break;
case grecs_callback_section_end:
ntf = *pdata;
- if (!ntf->msg)
+ if (!ntf->msg && !ntf->modname)
grecs_error(locus, 0, _("missing message definition"));
else {
struct notification **p =
@@ -876,11 +899,12 @@ string_to_dictionary_type(const char *str)
}
static int
-cb_dictionary_type(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_dictionary_type(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
enum dictionary_type *ptype = varptr;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -892,12 +916,13 @@ cb_dictionary_type(enum grecs_callback_command cmd,
}
static int
-cb_dictionary_params(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_dictionary_params(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct dictionary *meth = varptr;
size_t size;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (cmd != grecs_callback_set_value) {
grecs_error(locus, 0, _("Unexpected block statement"));
@@ -968,13 +993,14 @@ string_to_dictionary_id(grecs_locus_t *locus,
}
static int
-cb_dictionary(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_dictionary(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct dictionary **pmeth, *meth;
void **pdata = cb_data;
enum dictionary_id id;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
switch (cmd) {
case grecs_callback_section_begin:
@@ -1023,12 +1049,13 @@ cb_dictionary(enum grecs_callback_command cmd,
}
static int
-cb_url(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_url(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
mu_url_t *purl = varptr, url;
int rc;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -1079,18 +1106,18 @@ static struct grecs_keyword spool_kw[] = {
{ "check-script", NULL, N_("A /bin/sh script to verify the tarball"),
grecs_type_string, GRECS_DFLT,
NULL, offsetof(struct spool, check_script) },
-
{ NULL }
};
static int
-cb_spool(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct spool *spool;
void **pdata = cb_data;
int rc, ec, i;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
switch (cmd) {
case grecs_callback_section_begin:
@@ -1165,11 +1192,12 @@ cb_spool(enum grecs_callback_command cmd,
}
static int
-cb_user(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
struct passwd *pw;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -1187,10 +1215,12 @@ cb_user(enum grecs_callback_command cmd,
}
static int
-cb_supp_groups(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
if (cmd != grecs_callback_set_value) {
grecs_error(locus, 0, _("Unexpected block statement"));
return 1;
@@ -1244,10 +1274,12 @@ static struct grecs_keyword locking_kw[] = {
};
static int
-cb_locking(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_locking(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
if (cmd == grecs_callback_set_value) {
if (!value || value->type != GRECS_TYPE_STRING) {
grecs_error(value ? &value->locus : locus, 0,
@@ -1261,11 +1293,12 @@ cb_locking(enum grecs_callback_command cmd,
}
static int
-cb_upload_version(enum grecs_callback_command cmd,
- grecs_locus_t *locus,
- void *varptr, grecs_value_t *value, void *cb_data)
+cb_upload_version(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
unsigned *pversion = varptr, n;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
if (assert_string_arg(locus, cmd, value))
return 1;
@@ -1300,6 +1333,20 @@ static struct grecs_keyword wydawca_kw[] = {
{ "pidfile", N_("file"), N_("Set pid file name"),
grecs_type_string, GRECS_DFLT, &pidfile },
+ { "module-prepend-load-path", N_("path"),
+ N_("List of directories searched for modules prior to "
+ "the default module directory"),
+ grecs_type_string, GRECS_LIST,
+ &module_prepend_load_path },
+ { "module-load-path", N_("path"),
+ N_("List of directories searched for database modules."),
+ grecs_type_string, GRECS_LIST,
+ &module_load_path },
+
+ { "module", N_("name: string> <path: string"),
+ N_("Load the specified module"),
+ grecs_type_string, GRECS_MULT, NULL, 0, cb_module },
+
{ "inotify", NULL, N_("Enable or disable inotify support"),
grecs_type_bool, GRECS_DFLT, &inotify_enable },
diff --git a/src/mail.c b/src/mail.c
index 2b64501..dd16510 100644
--- a/src/mail.c
+++ b/src/mail.c
@@ -509,6 +509,11 @@ do_notify(struct file_triplet *trp, enum notification_event ev,
const char *errp;
const char *msg;
+ if (ntf->modname) {
+ module_notify(ntf->modname, ntf->modcfg, ev, trp);
+ return;
+ }
+
switch (ntf->tgt) {
case notify_read:
rcpt = NULL;
diff --git a/src/module.c b/src/module.c
new file mode 100644
index 0000000..41bbb39
--- a/dev/null
+++ b/src/module.c
@@ -0,0 +1,236 @@
+/* wydawca - automatic release submission daemon
+ Copyright (C) 2007-2012 Sergey Poznyakoff
+
+ Wydawca is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Wydawca is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with wydawca. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "wydawca.h"
+#include <ltdl.h>
+
+static struct grecs_symtab *modtab;
+struct grecs_list *module_load_path, *module_prepend_load_path;
+
+static void
+modfree(void *p)
+{
+ struct module *mod = p;
+ free(mod->locus.beg.file);
+ free(mod->locus.end.file);
+ free(mod->path);
+ free(mod->name);
+ free(mod);
+}
+
+static struct module *
+modinstall(const char *name, const char *path, grecs_locus_t *loc)
+{
+ struct module key;
+ struct module *ent;
+ int install = 1;
+
+ if (!modtab) {
+ modtab = grecs_symtab_create(sizeof(struct module),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ modfree);
+ if (!modtab)
+ grecs_alloc_die();
+ }
+
+ key.name = (char*) name;
+ ent = grecs_symtab_lookup_or_install(modtab, &key, &install);
+ if (!ent)
+ grecs_alloc_die();
+ if (install == 0) {
+ grecs_error(loc, 0, _("module %s already declared"), name);
+ grecs_error(&ent->locus, 0, _("previously declared here"));
+ return NULL;
+ }
+ ent->path = grecs_strdup(path);
+ ent->locus.beg.file = grecs_strdup(loc->beg.file);
+ ent->locus.beg.line = loc->beg.line;
+ ent->locus.beg.col = loc->beg.col;
+ ent->locus.end.file = grecs_strdup(loc->end.file);
+ ent->locus.end.line = loc->end.line;
+ ent->locus.end.col = loc->end.col;
+ return ent;
+}
+
+static struct module *
+modlookup(const char *name)
+{
+ struct module key;
+
+ if (!modtab)
+ return NULL;
+
+ key.name = (char*) name;
+ return grecs_symtab_lookup_or_install(modtab, &key, NULL);
+}
+
+int
+cb_module(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ grecs_value_t *name;
+ grecs_value_t *path;
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
+ if (cmd != grecs_callback_set_value) {
+ grecs_error(locus, 0, _("Unexpected block statement"));
+ return 1;
+ }
+
+ if (!(name = get_arg(value, 0, GRECS_TYPE_STRING)))
+ return 1;
+ if (!(path = get_arg(value, 1, GRECS_TYPE_STRING)))
+ return 1;
+
+ modinstall(name->v.string, path->v.string, locus);
+
+ return 0;
+};
+
+static void *
+resolve_sym(struct module *mod, const char *name)
+{
+ void *sym = lt_dlsym(mod->handle, name);
+ if (!sym) {
+ grecs_error(&mod->locus, 0,
+ _("module \"%s\" does not define symbol \"%s\""),
+ mod->name, name);
+ }
+ return sym;
+}
+
+static int
+modload(void *sym, void *data)
+{
+ struct module *mod = sym;
+ lt_dlhandle handle = NULL;
+ lt_dladvise advise = data;
+
+ if (mod->handle) {
+ grecs_error(&mod->locus, 0, _("already loaded"));
+ return 0;
+ }
+
+ handle = lt_dlopenadvise(mod->path, advise);
+
+ if (!handle) {
+ grecs_error(&mod->locus, 0,
+ _("cannot load module %s: %s"), mod->path,
+ lt_dlerror());
+ return 1;
+ }
+ mod->handle = handle;
+ mod->config = resolve_sym(mod, "config");
+ mod->notify = resolve_sym(mod, "notify");
+
+ return 0;
+}
+
+static int
+spoolmodcfg(struct spool *spool, void *unused)
+{
+ struct notification *np;
+
+ for (np = spool->notification; np; np = np->next) {
+ if (np->modname) {
+ struct module *mod = modlookup(np->modname);
+ if (!mod) {
+ logmsg(LOG_ERR, "spool %s: no such module: %s",
+ spool->tag, np->modname);
+ return 1;
+ }
+ if (mod->config) {
+ np->modcfg = mod->config(np->modnode);
+ if (!np->modcfg) {
+ logmsg(LOG_ERR,
+ "spool %s: failed to configure "
+ "module \"%s\"",
+ spool->tag, np->modname);
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+modules_load()
+{
+ lt_dladvise advise = NULL;
+ struct grecs_list_entry *ep;
+
+ if (lt_dlinit()) {
+ logmsg(LOG_ERR, _("failed to initialize libtool"));
+ return;
+ }
+
+ /* Prepare load path */
+ if (module_prepend_load_path)
+ for (ep = module_prepend_load_path->head; ep; ep = ep->next)
+ lt_dladdsearchdir(ep->data);
+ lt_dladdsearchdir(WYDAWCA_MODDIR);
+ if (module_load_path)
+ for (ep = module_load_path->head; ep; ep = ep->next)
+ lt_dladdsearchdir(ep->data);
+
+
+ if (lt_dladvise_init(&advise))
+ logmsg(LOG_ERR, "lt_dladvise_init: %s", lt_dlerror());
+ else {
+ if (lt_dladvise_ext(&advise))
+ logmsg(LOG_ERR, "lt_dladvise_ext: %s", lt_dlerror());
+ if (lt_dladvise_global(&advise))
+ logmsg(LOG_ERR, "lt_dladvise_global: %s",
+ lt_dlerror());
+ }
+ if (grecs_symtab_enumerate(modtab, modload, NULL)) {
+ logmsg(LOG_CRIT, _("some modules failed to load, exiting"));
+ exit(EX_UNAVAILABLE);
+ }
+ lt_dladvise_destroy(&advise);
+
+ if (for_each_spool(spoolmodcfg, NULL)) {
+ logmsg(LOG_CRIT,
+ _("some modules failed to configure, exiting"));
+ exit(EX_UNAVAILABLE);
+ }
+}
+
+static char *
+getfn(void *trp, const char *fmt)
+{
+ return triplet_expand_param(fmt, trp);
+}
+
+void
+module_notify(const char *name, void *modcfg,
+ enum notification_event ev, struct file_triplet *trp)
+{
+ struct module *mod = modlookup(name);
+
+ if (!mod) {
+ logmsg(LOG_ERR, "no such module: %s", name);
+ return;
+ }
+ if (mod->notify)
+ mod->notify(modcfg, ev, getfn, trp);
+}
+
diff --git a/src/tcpwrap.c b/src/tcpwrap.c
index 907bc20..4a3e59b 100644
--- a/src/tcpwrap.c
+++ b/src/tcpwrap.c
@@ -26,10 +26,12 @@ int deny_severity = LOG_INFO;
int allow_severity = LOG_INFO;
static int
-cb_syslog_priority(enum grecs_callback_command cmd,
- grecs_locus_t * locus,
- void *varptr, grecs_value_t * value, void *cb_data)
+cb_syslog_priority(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+
if (assert_string_arg(locus, cmd, value))
return 1;
diff --git a/src/wydawca.c b/src/wydawca.c
index 42fcea9..f6767b8 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -358,6 +358,7 @@ main(int argc, char **argv)
exit(EX_CONFIG);
config_finish(tree);
+ modules_load();
grecs_tree_free(tree);
if (lint_mode)
diff --git a/src/wydawca.h b/src/wydawca.h
index 9e4b2be..8e2f155 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -291,6 +291,9 @@ struct notification {
enum notification_target tgt;
const char *sign_keys;
const char *msg;
+ char *modname;
+ void *modcfg;
+ grecs_node_t *modnode;
};
void register_message_template(const char *name, const char *text);
@@ -316,6 +319,27 @@ void meta_free(struct metadef *def);
const char *expand_email_admin(struct metadef *def, void *data);
const char *expand_email_owner(struct metadef *def, void *data);
+/* Modules */
+typedef char *(*format_fn)(void *, const char *);
+
+struct module {
+ char *name;
+ char *path;
+ grecs_locus_t locus;
+ void *handle;
+ void *(*config) (grecs_node_t *);
+ int (*notify) (void *, int, format_fn, void *);
+};
+
+int cb_module(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data);
+void modules_load(void);
+
+extern struct grecs_list *module_load_path, *module_prepend_load_path;
+void module_notify(const char *name, void *modcfg,
+ enum notification_event ev, struct file_triplet *tpl);
+
+
/* Global variables */
extern char *program_name;
extern uid_t wydawca_uid;
@@ -483,6 +507,8 @@ void config_finish(struct grecs_node *);
void config_help(void);
int assert_string_arg(grecs_locus_t *, enum grecs_callback_command,
const grecs_value_t *);
+grecs_value_t *get_arg(grecs_value_t *value, unsigned n, int type);
+
/* vtab.c */
int url_to_vtab(mu_url_t url, struct virt_tab *vtab);

Return to:

Send suggestions and report system problems to the System administrator.