-.section "Dynamically loaded lookup module support" "SECTdynamicmodules"
+.section "Dynamically loaded module support" "SECTdynamicmodules"
.cindex "lookup modules"
+.cindex "router modules"
.cindex "dynamic modules"
.cindex ".so building"
On some platforms, Exim supports not compiling all lookup types directly into
dependencies.
Most, but not all, lookup types can be built this way.
+.new
+Similarly, router drivers can be built as external modules.
+This permits a smaller exim binary, growing only as needed for the
+runtime cofiguration.
+.wen
+
Set &`LOOKUP_MODULE_DIR`& to the directory into which the modules will be
installed; Exim will only load modules from that directory, as a security
measure. You will need to set &`CFLAGS_DYNAMIC`& if not already defined
3. Events smtp:fail:protocol and smtp:fail:syntax
- 4. JSON lookup support can now be built as a lodable module
+ 4. JSON lookup support, and all the router driver except manualroute,
+ can now be built as lodable modules
Version 4.98
------------
# up-to-date. Then the os-specific source files and the C configuration file
# are set up, and finally it goes to the main Exim target.
-all: utils exim
+all: utils exim dynmodules
config: $(EDITME) checklocalmake Makefile os.c config.h version.h version.sh macro.c
exim_openssl exim_gnutls: clean exim
.PHONY: all config utils \
buildauths buildlookups buildpdkim buildrouters \
- buildtransports checklocalmake clean
+ buildtransports dynmodules checklocalmake clean
utils: $(EXIM_MONITOR) exicyclog exinext exiwhat \
# Targets for the various libraries that Exim uses.
+# Copies of modules built as dynamic-load libraries
+
+dynmodules: buildlookups buildrouters buildtransports buildauths
+ rm -fr dynmodules
+ mkdir dynmodules
+ for d in lookup router transport auth; do \
+ for f in $${d}s/*.so; do \
+ [ -e $$f ] && ln $$f dynmodules/`basename $$f .so`_$$d.so; \
+ done; \
+ done; \
+ true
+
# The lookups library.
buildlookups: config
buildrouters: config
@cd routers && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \
FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
@echo " "
buildtransports: config
@cd transports && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \
FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
@echo " "
buildauths: config
@cd auths && $(MAKE) SHELL=$(SHELL) AR="$(AR)" $(MFLAGS) CC="$(CC)" CFLAGS="$(CFLAGS)" \
+ CFLAGS_DYNAMIC="$(CFLAGS_DYNAMIC)" \
FE="$(FE)" RANLIB="$(RANLIB)" RM_COMMAND="$(RM_COMMAND)" HDRS="$(PHDRS)" \
INCLUDE="$(INCLUDE) $(IPV6_INCLUDE) $(TLS_INCLUDE)"
@echo " "
# just got too horrendous to get it right in "make", because of the optionally
# existing configuration files.
#
-# Copyright (c) The Exim Maintainers 1995 - 2021
+# Copyright (c) The Exim Maintainers 1995 - 2024
# SPDX-License-Identifier: GPL-2.0-or-later
cp ../src/lookups/Makefile $look_mf_pre
../scripts/lookups-Makefile
+class="routers"
+cp ../src/$class/Makefile $class/Makefile.predynamic
+../scripts/$class-Makefile
+mv routers/Makefile.postdynamic $class/Makefile
+rm $class/Makefile.predynamic
+class=
+
# See if there is a definition of EXIM_PERL in what we have built so far.
# If so, run Perl to find the default values for PERL_CC, PERL_CCOPTS,
# and PERL_LIBS. These need to be put at the top of the Makefile, so we rename
d="routers"
mkdir $d
cd $d
-for f in README Makefile accept.h accept.c dnslookup.h dnslookup.c \
+# Makefile is generated
+for f in README accept.h accept.c dnslookup.h dnslookup.c \
ipliteral.h ipliteral.c iplookup.h iplookup.c manualroute.h \
manualroute.c queryprogram.h queryprogram.c redirect.h redirect.c \
rf_functions.h rf_change_domain.c rf_expand_data.c rf_get_errors_address.c \
--- /dev/null
+#! /bin/sh
+
+# Copyright (c) The Exim Maintainers 1995 - 2021
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# We turn the configure-built build-$foo/routers/Makefile.predynamic into Makefile
+
+# We always re-exec ourselves at least once, because it's the cleanest and
+# most portable way to turn on various features we expect of POSIX sh.
+if [ -z "$EXIM_ROUTER_MAKEFILE_ADJUSTED" ]
+then
+ SHELL=/bin/sh
+ EXIM_ROUTER_MAKEFILE_ADJUSTED=yes
+ export EXIM_ROUTER_MAKEFILE_ADJUSTED
+
+ # Solaris sh and tr are problematic until we get xpg4 variants
+ if [ -x /usr/xpg4/bin/sh ]
+ then
+ PATH="/usr/xpg4/bin:$PATH"
+ export PATH
+ SHELL=/usr/xpg4/bin/sh
+ export SHELL
+ fi
+
+ # IRIX uses /bin/ksh for sh but in a compatibility mode unless $_XPG == 1,
+ # where said compatibility mode disables $(...)
+ _XPG=1
+ export _XPG
+
+ # We need the _right_ tr, so must do that first; but if a shell which
+ # we're more confident is sane is available, let's try that. Mostly,
+ # the problem is that "local" is not actually in "the" standard, it's
+ # just in every not-insane shell. Though arguably, there are no shells
+ # with POSIX-ish syntax which qualify as "not insane".
+ for b in /bin/dash /bin/bash /usr/local/bin/bash
+ do
+ if [ -x "$b" ]
+ then
+ SHELL="$b"
+ break
+ fi
+ done
+ # if we get a report of a system with zsh but not bash, we can add that
+ # to the list, but be sure to enable sh_word_split in that case.
+
+ exec "$SHELL" "$0" "$@"
+fi
+
+input=routers/Makefile.predynamic
+target=routers/Makefile.postdynamic
+defs_source=Makefile-t
+tag_marker='MAGIC-TAG-MODS-OBJ-RULES-GO-HERE'
+
+tab=' '
+
+# We rely on tr(1) for translating case below. Some people export
+# values of LC_CTYPE and LC_COLLATE which apparently break our assumptions.
+# We're a script expecting certain output based on known inputs and not dealing
+# with UTF8, so we should be safe doing this:
+LC_ALL=C
+export LC_ALL
+
+if [ -f "$defs_source" ]
+then
+ :
+ # we are happy
+else
+ echo >&2 "$0: ERROR: MISSING FILE '${defs_source}'"
+ echo >&2 "$0: SHOULD HAVE BEEN CALLED FROM scripts/Configure-Makefile"
+ exit 1
+fi
+
+# nb: do not permit leading whitespace for this, as CFLAGS_DYNAMIC is exported
+# to the lookups subdir via a line with leading whitespace which otherwise
+# matches
+if grep -q "^CFLAGS_DYNAMIC[ $tab?:]*=" "$defs_source"
+then
+ # we have a definition, we're good to go
+ echo >&2 ">>> Creating routers/Makefile for building dynamic modules"
+ enable_dynamic=yes
+else
+ echo >&2 ">>> Creating routers/Makefile without dynamic module support"
+ enable_dynamic=''
+ # We always do something now, since there should always be a lookup,
+ # and now we need to run in order to put the OBJ=$(OBJ)+ rules in. So we
+ # continue on.
+fi
+
+# For the want_ checks, we need to let the user override values from the make
+# command-line, not just check the Makefile.
+
+want_dynamic() {
+ local dyn_name="$1"
+ local re="ROUTER_${dyn_name}[ $tab]*=[ $tab]*2"
+ env | grep -q "^$re"
+ if [ $? -eq 0 ]; then return 0; fi
+ grep -q "^[ $tab]*$re" "$defs_source"
+}
+
+want_at_all() {
+ local want_name="$1"
+ local re="ROUTER_${want_name}[ $tab]*=[ $tab]*."
+ env | grep -q "^$re"
+ if [ $? -eq 0 ]; then return 0; fi
+ grep -q "^[ $tab]*$re" "$defs_source"
+}
+
+# Adapted want_at_all above to work for EXPERIMENTAL features
+want_experimental() {
+ local want_name="$1"
+ local re="EXPERIMENTAL_${want_name}[ $tab]*=[ $tab]*."
+ env | grep -q "^$re"
+ if [ $? -eq 0 ]; then return 0; fi
+ grep -q "^[ $tab]*$re" "$defs_source"
+}
+
+# The values of these variables will be emitted into the Makefile.
+
+MODS=""
+OBJ=""
+
+emit_module_rule() {
+ local name="$1"
+ local mod_name pkgconf
+ if [ "${name%:*}" = "$name" ]
+ then
+ # Square brackets are redundant but benign for POSIX compliant tr,
+ # however Solaris /usr/bin/tr requires them. Sometimes Solaris
+ # gets installed without a complete set of xpg4 tools, sigh.
+ mod_name=$(echo $name | tr [A-Z] [a-z])
+ else
+ mod_name="${name#*:}"
+ name="${name%:*}"
+ fi
+
+ if want_dynamic "$name"
+ then
+ if [ -z "$enable_dynamic" ]; then
+ echo >&2 "Missing CFLAGS_DYNAMIC prevents building dynamic $name"
+ exit 1
+ fi
+ MODS="${MODS} ${mod_name}.so"
+# pkgconf=$(grep "^ROUTER_${name}_PC" "$defs_source")
+# if [ $? -eq 0 ]; then
+# pkgconf=$(echo $pkgconf | sed 's/^.*= *//')
+# echo "ROUTER_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)"
+# echo "ROUTER_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)"
+# else
+# grep "^ROUTER_${name}_" "$defs_source"
+# echo "ROUTER_${mod_name}_INCLUDE = \$(ROUTER_${name}_INCLUDE)"
+# echo "ROUTER_${mod_name}_LIBS = \$(ROUTER_${name}_LIBS)"
+# fi
+ elif want_at_all "$name"
+ then
+ OBJ="${OBJ} ${mod_name}.o"
+ fi
+}
+
+rm -f "$target"
+exec 5>&1
+exec > "$target"
+
+sed -n "1,/$tag_marker/p" < "$input"
+
+for name_mod in \
+ ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
+do
+ emit_module_rule $name_mod
+done
+
+echo "MODS = $MODS"
+echo "OBJ = $OBJ"
+
+sed -n "/$tag_marker/,\$p" < "$input"
+
+exec >&5
+
+# Configure-Makefile will move $target into place
+
+# vim: set ft=sh sw=2 :
# It has also to be configured in the run time configuration file. By
# commenting out those you know you don't want to use, you can make the binary
# a bit smaller. If you are unsure, leave all of these included for now.
+#
+# If set to "2" instead of "yes" then the corresponding driver will be
+# built as a module and must be installed into LOOKUP_MODULE_DIR (the name
+# is historic).
+# You need to add -export-dynamic -rdynamic to EXTRALIBS. You may also need to
+# add -ldl to EXTRALIBS so that dlopen() is available to Exim. You need to
+# define CFLAGS_DYNAIC and LOOKUP_MODULE_DIR below so the builds are done right,
+# and so the exim binary actually loads dynamic lookup modules.
+# MANUALROUTE cannot currently be built as a module.
ROUTER_ACCEPT=yes
ROUTER_DNSLOOKUP=yes
#include "auths/tls.h"
#endif
-auth_info auths_available[] = {
+auth_info * auths_available_newlist = NULL;
+auth_info auths_available_oldarray[] = {
/* Checking by an expansion condition on plain text */
#include "routers/rf_functions.h"
-#ifdef ROUTER_ACCEPT
-# include "routers/accept.h"
-#endif
-
-#ifdef ROUTER_DNSLOOKUP
-# include "routers/dnslookup.h"
-#endif
-
-#ifdef ROUTER_MANUALROUTE
-# include "routers/manualroute.h"
-#endif
-
-#ifdef ROUTER_IPLITERAL
-# include "routers/ipliteral.h"
-#endif
-
-#ifdef ROUTER_IPLOOKUP
-# include "routers/iplookup.h"
-#endif
-
-#ifdef ROUTER_QUERYPROGRAM
-# include "routers/queryprogram.h"
-#endif
-
-#ifdef ROUTER_REDIRECT
-# include "routers/redirect.h"
-#endif
-
#ifdef TRANSPORT_APPENDFILE
# include "transports/appendfile.h"
#endif
#endif
-/* Now set up the structures, terminated by an entry with a null name. */
-
-router_info routers_available[] = {
-#ifdef ROUTER_ACCEPT
- {
- .drinfo = {
- .driver_name = US"accept",
- .options = accept_router_options,
- .options_count = &accept_router_options_count,
- .options_block = &accept_router_option_defaults,
- .options_len = sizeof(accept_router_options_block),
- .init = accept_router_init,
- },
- .code = accept_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = ri_yestransport
- },
-#endif
-#ifdef ROUTER_DNSLOOKUP
- {
- .drinfo = {
- .driver_name = US"dnslookup",
- .options = dnslookup_router_options,
- .options_count = &dnslookup_router_options_count,
- .options_block = &dnslookup_router_option_defaults,
- .options_len = sizeof(dnslookup_router_options_block),
- .init = dnslookup_router_init,
- },
- .code = dnslookup_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = ri_yestransport
- },
-#endif
-#ifdef ROUTER_IPLITERAL
- {
- .drinfo = {
- .driver_name = US"ipliteral",
- .options = ipliteral_router_options,
- .options_count = &ipliteral_router_options_count,
- .options_block = &ipliteral_router_option_defaults,
- .options_len = sizeof(ipliteral_router_options_block),
- .init = ipliteral_router_init,
- },
- .code = ipliteral_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = ri_yestransport
- },
-#endif
-#ifdef ROUTER_IPLOOKUP
- {
- .drinfo = {
- .driver_name = US"iplookup",
- .options = iplookup_router_options,
- .options_count = &iplookup_router_options_count,
- .options_block = &iplookup_router_option_defaults,
- .options_len = sizeof(iplookup_router_options_block),
- .init = iplookup_router_init,
- },
- .code = iplookup_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = ri_notransport
- },
-#endif
-#ifdef ROUTER_MANUALROUTE
- {
- .drinfo = {
- .driver_name = US"manualroute",
- .options = manualroute_router_options,
- .options_count = &manualroute_router_options_count,
- .options_block = &manualroute_router_option_defaults,
- .options_len = sizeof(manualroute_router_options_block),
- .init = manualroute_router_init,
- },
- .code = manualroute_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = 0
- },
-#endif
-#ifdef ROUTER_QUERYPROGRAM
- {
- .drinfo = {
- .driver_name = US"queryprogram",
- .options = queryprogram_router_options,
- .options_count = &queryprogram_router_options_count,
- .options_block = &queryprogram_router_option_defaults,
- .options_len = sizeof(queryprogram_router_options_block),
- .init = queryprogram_router_init,
- },
- .code = queryprogram_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = 0
- },
-#endif
-#ifdef ROUTER_REDIRECT
- {
- .drinfo = {
- .driver_name = US"redirect",
- .options = redirect_router_options,
- .options_count = &redirect_router_options_count,
- .options_block = &redirect_router_option_defaults,
- .options_len = sizeof(redirect_router_options_block),
- .init = redirect_router_init,
- },
- .code = redirect_router_entry,
- .tidyup = NULL, /* no tidyup entry */
- .ri_flags = ri_notransport
- },
-#endif
- { .drinfo = { .driver_name = US"" }}
-};
+router_info * routers_available = NULL;
-
-transport_info transports_available[] = {
+transport_info * transports_available_newlist = NULL;
+transport_info transports_available_oldarray[] = {
#ifdef TRANSPORT_APPENDFILE
{
.drinfo = {
auth_show_supported(gstring * g)
{
g = string_cat(g, US"Authenticators:");
-for (auth_info * ai = auths_available; ai->drinfo.driver_name[0]; ai++)
+for (auth_info * ai = auths_available_oldarray; ai->drinfo.driver_name[0]; ai++)
g = string_fmt_append(g, " %s", ai->drinfo.driver_name);
return string_cat(g, US"\n");
}
gstring *
route_show_supported(gstring * g)
{
-g = string_cat(g, US"Routers:");
-for (router_info * rr = routers_available; rr->drinfo.driver_name[0]; rr++)
- g = string_fmt_append(g, " %s", rr->drinfo.driver_name);
-return string_cat(g, US"\n");
+uschar * b = US"" /* static-build router names */
+#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
+ " accept"
+#endif
+#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
+ " dnslookup"
+#endif
+# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
+ " ipliteral"
+#endif
+#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
+ " iplookup"
+#endif
+#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
+ " manualroute"
+#endif
+#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
+ " redirect"
+#endif
+#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
+ " queryprogram"
+#endif
+ ;
+
+uschar * d = US"" /* dynamic-module router names */
+#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT==2
+ " accept"
+#endif
+#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP==2
+ " dnslookup"
+#endif
+# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL==2
+ " ipliteral"
+#endif
+#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP==2
+ " iplookup"
+#endif
+#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE==2
+ " manualroute"
+#endif
+#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT==2
+ " redirect"
+#endif
+#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM==2
+ " queryprogram"
+#endif
+ ;
+
+if (*b) g = string_fmt_append(g, "Routers (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Routers (dynamic): %s\n", d);
+return g;
}
gstring *
init_lookup_list(void)
{
#ifdef LOOKUP_MODULE_DIR
-DIR *dd;
-struct dirent *ent;
+DIR * dd;
+struct dirent * ent;
int countmodules = 0;
int moduleerrors = 0;
#endif
addlookupmodule(NULL, &whoson_lookup_module_info);
#endif
+/* This is a custom expansion, and not available as either
+a list-syntax lookup or a lookup expansion. However, it is
+implemented by a lookup module. */
+
addlookupmodule(NULL, &readsock_lookup_module_info);
#ifdef LOOKUP_MODULE_DIR
if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
{
DEBUG(D_lookup) debug_printf("Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
- log_write(0, LOG_MAIN, "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "Couldn't open %s: not loading lookup modules\n", LOOKUP_MODULE_DIR);
}
else
{
const pcre2_code * regex_islookupmod = regex_must_compile(
- US"\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
+ US"_lookup\\." DYNLIB_FN_EXT "$", MCS_NOFLAGS, TRUE);
DEBUG(D_lookup) debug_printf("Loading lookup modules from %s\n", LOOKUP_MODULE_DIR);
while ((ent = readdir(dd)))
show_string(is_stdout, g);
g = NULL;
-for (auth_info * ai= auths_available; *ai->drinfo.driver_name != '\0'; ai++)
+//for (auth_info * ai= auths_available; *ai->drinfo.driver_name != '\0'; ai++)
+for (auth_info * ai = auths_available_newlist; ai; ai = (auth_info *)ai->drinfo.next)
if (ai->version_report)
g = (*ai->version_report)(g);
extern tree_node *acl_var_create(uschar *);
extern void acl_var_write(uschar *, uschar *, void *);
+extern void add_driver_info(driver_info **, const driver_info *, size_t);
+
#ifdef EXPERIMENTAL_ARC
# ifdef SUPPORT_DMARC
uschar **, error_block **, int *, const uschar *);
extern int rda_is_filter(const uschar *);
extern BOOL readconf_depends(driver_instance *, uschar *);
-extern void readconf_driver_init(uschar *, driver_instance **,
- driver_info *, int, void *, int, optionlist *, int);
+extern void readconf_driver_init(driver_instance **, driver_info **, int,
+ void *, int, optionlist *, int, const uschar *);
extern const uschar *readconf_find_option(void *);
extern void readconf_main(BOOL);
extern void readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *);
extern BOOL authentication_failed; /* TRUE if AUTH was tried and failed */
extern uschar *authenticator_name; /* for debug and error messages */
extern uschar *auth_advertise_hosts; /* Only advertise to these */
-extern auth_info auths_available[]; /* Vector of available auth mechanisms */
+extern auth_info auths_available_oldarray[]; /* Vector of available auth mechanisms */
+extern auth_info * auths_available_newlist;
extern auth_instance *auths; /* Chain of instantiated auths */
extern auth_instance auth_defaults; /* Default values */
extern uschar *auth_defer_msg; /* Error message for log */
/* extern BOOL rfc821_domains; */ /* If set, syntax is 821, not 822 => being abolished */
extern uid_t root_gid; /* The gid for root */
extern uid_t root_uid; /* The uid for root */
-extern router_info routers_available[];/* Vector of available routers */
+extern router_info *routers_available; /* List of available router drivers */
extern router_instance *routers; /* Chain of instantiated routers */
extern router_instance router_defaults;/* Default values */
extern const uschar *router_name; /* Name of router last started */
extern const uschar **transport_filter_argv; /* For on-the-fly filtering */
extern int transport_filter_timeout; /* Timeout for same */
-extern transport_info transports_available[]; /* Vector of available transports */
+extern transport_info transports_available_oldarray[]; /* Vector of available transports */
+extern transport_info * transports_available_newlist;
extern transport_instance *transports; /* Chain of instantiated transports */
extern transport_instance transport_defaults; /* Default values */
# This is called from the main make file, after cd'ing
# to the lookups subdirectory.
#
-# Copyright (c) The Exim Maintainers 2021
+# Copyright (c) The Exim Maintainers 2021 - 2024
# nb: at build time, the version of this file used will have had some
# extra variable definitions and prepended to it and module build rules
-# interpolated below.
+# interpolated below. This is done by scripts/lookups-Makefile.
# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE
lf_quote.o: $(HDRS) lf_quote.c lf_functions.h
lf_sqlperform.o: $(HDRS) lf_sqlperform.c lf_functions.h
-cdb.o: $(HDRS) cdb.c
-dbmdb.o: $(HDRS) dbmdb.c
-dnsdb.o: $(HDRS) dnsdb.c
-dsearch.o: $(HDRS) dsearch.c
-ibase.o: $(HDRS) ibase.c
-ldap.o: $(HDRS) ldap.c
-lmdb.o: $(HDRS) lmdb.c
-json.o: $(HDRS) json.c
-lsearch.o: $(HDRS) lsearch.c
-mysql.o: $(HDRS) mysql.c
-nis.o: $(HDRS) nis.c
-nisplus.o: $(HDRS) nisplus.c
-oracle.o: $(HDRS) oracle.c
-passwd.o: $(HDRS) passwd.c
-pgsql.o: $(HDRS) pgsql.c
-readsock.o: $(HDRS) readsock.c
-redis.o: $(HDRS) redis.c
-spf.o: $(HDRS) spf.c
-sqlite.o: $(HDRS) sqlite.c
-testdb.o: $(HDRS) testdb.c
-whoson.o: $(HDRS) whoson.c
-
-cdb.so: $(HDRS) cdb.c
-dbmdb.so: $(HDRS) dbmdb.c
-dnsdb.so: $(HDRS) dnsdb.c
-dsearch.so: $(HDRS) dsearch.c
-ibase.so: $(HDRS) ibase.c
-json.so: $(HDRS) json.c
-ldap.so: $(HDRS) ldap.c
-lmdb.so: $(HDRS) lmdb.c
-lsearch.so: $(HDRS) lsearch.c
-mysql.so: $(HDRS) mysql.c
-nis.so: $(HDRS) nis.c
-nisplus.so: $(HDRS) nisplus.c
-oracle.so: $(HDRS) oracle.c
-passwd.so: $(HDRS) passwd.c
-pgsql.so: $(HDRS) pgsql.c
-redis.so: $(HDRS) redis.c
-spf.so: $(HDRS) spf.c
-sqlite.so: $(HDRS) sqlite.c
-testdb.so: $(HDRS) testdb.c
-whoson.so: $(HDRS) whoson.c
+cdb.o cdb.so: $(HDRS) cdb.c
+dbmdb.o dbmdb.so: $(HDRS) dbmdb.c
+dnsdb.o dnsdb.so: $(HDRS) dnsdb.c
+dsearch.o dsearch.so: $(HDRS) dsearch.c
+ibase.o ibase.so: $(HDRS) ibase.c
+ldap.o ldap.so: $(HDRS) ldap.c
+lmdb.o lmdb.so: $(HDRS) lmdb.c
+json.o json.so: $(HDRS) json.c
+lsearch.o lsearch.so: $(HDRS) lsearch.c
+mysql.o mysql.so: $(HDRS) mysql.c
+nis.o nis.so: $(HDRS) nis.c
+nisplus.o nisplus.so: $(HDRS) nisplus.c
+oracle.o oracle.so: $(HDRS) oracle.c
+passwd.o passwd.so: $(HDRS) passwd.c
+pgsql.o pgsql.so: $(HDRS) pgsql.c
+readsock.o readsock.so: $(HDRS) readsock.c
+redis.o redis.so: $(HDRS) redis.c
+spf.o spf.so: $(HDRS) spf.c
+sqlite.o sqlite.so: $(HDRS) sqlite.c
+testdb.o testdb.so: $(HDRS) testdb.c
+whoson.o whoson.so: $(HDRS) whoson.c
# End
};
#ifdef DYNLOOKUP
-#define cdb_lookup_module_info _lookup_module_info
+# define cdb_lookup_module_info _lookup_module_info
#endif
static lookup_info *_lookup_list[] = { &cdb_lookup_info };
options_from_list(optionlist_auths, optionlist_auths_size,
US"AUTHENTICATORS", NULL);
+#ifdef old
for (struct auth_info * ai = auths_available; ai->drinfo.driver_name[0]; ai++)
+#endif
+for (driver_info * di = (driver_info *)auths_available_newlist; di; di = di->next)
{
- driver_info * di = &ai->drinfo;
+ auth_info * ai = (auth_info *)di;
+
spf(buf, sizeof(buf), US"_DRIVER_AUTHENTICATOR_%T", di->driver_name);
builtin_macro_create(buf);
options_from_list(di->options, (unsigned)*di->options_count,
+/* Add a driver info struct to a list. */
+
+void
+add_driver_info(driver_info ** drlist_p, const driver_info * newent,
+ size_t size)
+{
+driver_info * listent = store_get(size, newent);
+memcpy(listent, newent, size);
+listent->next = *drlist_p;
+*drlist_p= listent;
+}
+
/*************************************************
* Initialize one driver *
*************************************************/
Arguments:
d pointer to driver instance block, with generic
options filled in
- drivers_available vector of available drivers
+ info_anchor list of available drivers
size_of_info size of each block in drivers_available
- class class of driver, for error message
+ class class of driver
Returns: pointer to the driver info block
*/
static driver_info *
-init_driver(driver_instance *d, driver_info *drivers_available,
- int size_of_info, uschar *class)
+init_driver(driver_instance * d, driver_info ** info_anchor,
+ int size_of_info, const uschar * class)
{
-for (driver_info * dd = drivers_available; dd->driver_name[0] != 0;
- dd = (driver_info *)((US dd) + size_of_info))
- if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
+driver_info * di;
+int len;
+DIR * dd;
+
+/* First scan the list of statically-built drivers. */
+
+for (di = *info_anchor; di; di = di->next)
+ if (Ustrcmp(d->driver_name, di->driver_name) == 0)
+ goto found;
+
+#ifdef LOOKUP_MODULE_DIR
+/* Potentially a loadable module. Look for a file with the right name. */
+
+if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR);
+ }
+else
+ {
+ uschar * fname = string_sprintf("%s_%s." DYNLIB_FN_EXT, d->driver_name, class), * sname;
+ const char * errormsg;
+
+ DEBUG(D_any) debug_printf("Loading %s %s driver from %s\n",
+ d->driver_name, class, LOOKUP_MODULE_DIR);
+
+ for(struct dirent * ent; ent = readdir(dd); ) if (Ustrcmp(ent->d_name, fname) == 0)
{
- int len = dd->options_len;
- d->info = dd;
- d->options_block = store_get_perm(len, GET_UNTAINTED);
- memcpy(d->options_block, dd->options_block, len);
- for (int i = 0; i < *(dd->options_count); i++)
- dd->options[i].type &= ~opt_set;
- return dd;
+ void * dl = dlopen(CS string_sprintf(LOOKUP_MODULE_DIR "/%s", fname), RTLD_NOW);
+ static driver_magics dm[] = {
+ { ROUTER_MAGIC, US"router" },
+ { TRANSPORT_MAGIC, US"transport" },
+ { AUTH_MAGIC, US"auth" },
+ };
+
+ if (!dl)
+ {
+ errormsg = dlerror();
+ log_write(0, LOG_MAIN|LOG_PANIC, "Error loading %s %s driver: %s\n",
+ d->driver_name, class, errormsg);
+ break;
+ }
+ (void) dlerror(); /* cf. comment in init_lookup_list() */
+
+ di = (driver_info *) dlsym(dl, CS string_sprintf("_%s_info", class));
+ if ((errormsg = dlerror()))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s does not appear to be a %s module (%s)\n", fname, class, errormsg);
+ dlclose(dl);
+ break;
+ }
+ for(driver_magics * dmp = dm; dmp < dm + nelem(dm); dmp++)
+ if(Ustrcmp(dmp->class, class) == 0 && dmp->magic == di->dyn_magic)
+ {
+ int old_pool = store_pool;
+ store_pool = POOL_PERM;
+ add_driver_info(info_anchor, di, size_of_info);
+ store_pool = old_pool;
+ DEBUG(D_any) debug_printf("Loaded %s %s\n", d->driver_name, class);
+ closedir(dd);
+ goto found;
+ }
+
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s module %s is not compatible with this version of Exim\n",
+ class, d->driver_name);
+ dlclose(dl);
+ break;
}
+ closedir(dd);
+ }
+#endif /* LOOKUP_MODULE_DIR */
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"%s %s: cannot find %s driver \"%s\"", class, d->name, class, d->driver_name);
-return NULL; /* never obeyed */
+found:
+
+len = di->options_len;
+d->info = di;
+d->options_block = store_get_perm(len, GET_UNTAINTED);
+memcpy(d->options_block, di->options_block, len);
+for (int i = 0; i < *di->options_count; i++)
+ di->options[i].type &= ~opt_set;
+return di;
}
blocks for this shared code to work.
Arguments:
- class "router", "transport", or "authenticator"
anchor &routers, &transports, &auths
- drivers_available available drivers
+ info_anchor available drivers
size_of_info size of each info block
instance_default points to default data for an instance
instance_size size of instance block
driver_optionlist generic option list
driver_optionlist_count count of generic option list
+ class "router", "transport", or "authenticator"
+ for error message
Returns: nothing
*/
void
readconf_driver_init(
- uschar *class,
- driver_instance **anchor,
- driver_info *drivers_available,
+ driver_instance ** anchor,
+ driver_info ** info_anchor,
int size_of_info,
- void *instance_default,
+ void * instance_default,
int instance_size,
- optionlist *driver_optionlist,
- int driver_optionlist_count)
+ optionlist * driver_optionlist,
+ int driver_optionlist_count,
+ const uschar * class)
{
driver_instance ** p = anchor;
driver_instance * d = NULL;
driver_optionlist_count, d, NULL))
{
if (!d->info && d->driver_name)
- init_driver(d, drivers_available, size_of_info, class);
+ init_driver(d, info_anchor, size_of_info, class);
}
/* Handle private options - pass the generic block because some may
int nauths = 0;
#endif
-readconf_driver_init(US"authenticator",
- (driver_instance **)(&auths), /* chain anchor */
- (driver_info *)auths_available, /* available drivers */
+for (auth_info * tblent = auths_available_oldarray;
+ *tblent->drinfo.driver_name; tblent++)
+ {
+ driver_info * listent = store_get(sizeof(auth_info), tblent);
+ memcpy(listent, tblent, sizeof(auth_info));
+ listent->next = (driver_info *)auths_available_newlist;
+ auths_available_newlist = (auth_info *)listent;
+ }
+
+
+readconf_driver_init((driver_instance **)&auths, /* chain anchor */
+ (driver_info **)&auths_available_newlist, /* available drivers */
sizeof(auth_info), /* size of info block */
&auth_defaults, /* default values for generic options */
sizeof(auth_instance), /* size of instance block */
optionlist_auths, /* generic options */
- optionlist_auths_size);
+ optionlist_auths_size,
+ US"authenticator");
for (auth_instance * au = auths; au; au = au->drinst.next)
{
int mid = last/2;
int n = Ustrlen(next_section);
+ READCONF_DEBUG fprintf(stderr, "%s: %s\n", __FUNCTION__, next_section);
if (tolower(next_section[n-1]) != 's') Ustrcpy(next_section+n, US"s");
for (;;)
options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);
-for (router_info * ri = routers_available; ri->drinfo.driver_name[0]; ri++)
+for (driver_info * di = (driver_info *)routers_available; di; di = di->next)
{
- spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", ri->drinfo.driver_name);
+ spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", di->driver_name);
builtin_macro_create(buf);
- options_from_list(ri->drinfo.options, (unsigned)*ri->drinfo.options_count,
- US"ROUTER", ri->drinfo.driver_name);
+ options_from_list(di->options, (unsigned)*di->options_count,
+ US"ROUTER", di->driver_name);
}
}
void
route_init(void)
{
-readconf_driver_init(US"router",
- (driver_instance **)(&routers), /* chain anchor */
- (driver_info *)routers_available, /* available drivers */
+
+int old_pool = store_pool;
+store_pool = POOL_PERM;
+ {
+ driver_info ** anchor = (driver_info **) &routers_available;
+ extern router_info accept_router_info;
+ extern router_info dnslookup_router_info;
+ extern router_info ipliteral_router_info;
+ extern router_info iplookup_router_info;
+ extern router_info manualroute_router_info;
+ extern router_info redirect_router_info;
+ extern router_info queryprogram_router_info;
+
+ /* Add the router drivers that are built for static linkage to the
+ list of availables. */
+
+#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
+ add_driver_info(anchor, &accept_router_info.drinfo, sizeof(router_info));
+#endif
+#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
+ add_driver_info(anchor, &dnslookup_router_info.drinfo, sizeof(router_info));
+#endif
+# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
+ add_driver_info(anchor, &ipliteral_router_info.drinfo, sizeof(router_info));
+#endif
+#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
+ add_driver_info(anchor, &iplookup_router_info.drinfo, sizeof(router_info));
+#endif
+#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
+ add_driver_info(anchor, &manualroute_router_info.drinfo, sizeof(router_info));
+#endif
+#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
+ add_driver_info(anchor, &redirect_router_info.drinfo, sizeof(router_info));
+#endif
+#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
+ add_driver_info(anchor, &queryprogram_router_info.drinfo, sizeof(router_info));
+#endif
+ }
+store_pool = old_pool;
+
+
+/* Read the config file "routers" section, creating a routers instance list.
+For any yet-undiscovered driver, check for a loadable module and add it to
+those available. */
+
+readconf_driver_init((driver_instance **)&routers, /* chain anchor */
+ (driver_info **)&routers_available, /* available drivers */
sizeof(router_info), /* size of info blocks */
&router_defaults, /* default values for generic options */
sizeof(router_instance), /* size of instance block */
optionlist_routers, /* generic options */
- optionlist_routers_size);
+ optionlist_routers_size,
+ US"router");
for (router_instance * r = routers; r; r = r->drinst.next)
{
# calling it routers.a. This is called from the main make file, after cd'ing
# to the directors subdirectory. The library also contains functions that
# are called only from within the individual routers.
+#
+# Copyright (c) The Exim Maintainers 2021 - 2024
-OBJ = accept.o dnslookup.o ipliteral.o iplookup.o manualroute.o \
- queryprogram.o redirect.o \
- rf_change_domain.o rf_expand_data.o rf_get_errors_address.o \
+# nb: at build time, the version of this file used will have had some
+# extra variable definitions and prepended to it and module build rules
+# interpolated below. This is done by scripts/routers-Makefile.
+
+# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE
+
+RF_OBJ = rf_change_domain.o rf_expand_data.o rf_get_errors_address.o \
rf_get_munge_headers.o rf_get_transport.o rf_get_ugid.o \
rf_lookup_hostlist.o \
rf_queue_add.o rf_self_action.o \
rf_set_ugid.o
+OBJ += $(RF_OBJ)
+
+all: routers.a $(MODS)
+
routers.a: $(OBJ)
@$(RM_COMMAND) -f routers.a
@echo "$(AR) routers.a"
@$(AR) routers.a $(OBJ)
$(RANLIB) $@
-.SUFFIXES: .o .c
+.SUFFIXES: .o .c .so
.c.o:; @echo "$(CC) $*.c"
$(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c
-rf_change_domain.o: $(HDRS) rf_change_domain.c rf_functions.h
-rf_expand_data.o: $(HDRS) rf_expand_data.c rf_functions.h
-rf_get_errors_address.o: $(HDRS) rf_get_errors_address.c rf_functions.h
-rf_get_munge_headers.o: $(HDRS) rf_get_munge_headers.c rf_functions.h
-rf_get_transport.o: $(HDRS) rf_get_transport.c rf_functions.h
-rf_get_ugid.o: $(HDRS) rf_get_ugid.c rf_functions.h
-rf_lookup_hostlist.o: $(HDRS) rf_lookup_hostlist.c rf_functions.h
-rf_queue_add.o: $(HDRS) rf_queue_add.c rf_functions.h
-rf_self_action.o: $(HDRS) rf_self_action.c rf_functions.h
-rf_set_ugid.o: $(HDRS) rf_set_ugid.c rf_functions.h
-
-accept.o: $(HDRS) accept.c rf_functions.h accept.h
-dnslookup.o: $(HDRS) dnslookup.c rf_functions.h dnslookup.h
-ipliteral.o: $(HDRS) ipliteral.c rf_functions.h ipliteral.h
-iplookup.o: $(HDRS) iplookup.c rf_functions.h iplookup.h
-manualroute.o: $(HDRS) manualroute.c rf_functions.h manualroute.h
-queryprogram.o: $(HDRS) queryprogram.c rf_functions.h queryprogram.h
-redirect.o: $(HDRS) redirect.c rf_functions.h redirect.h
+.c.so:; @echo "$(CC) -shared $*.c"
+ $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
+
+
+
+$(OBJ) $(MOD): $(HDRS) rf_functions.h
+
+rf_change_domain.o: rf_change_domain.c
+rf_expand_data.o: rf_expand_data.c
+rf_get_errors_address.o: rf_get_errors_address.c
+rf_get_munge_headers.o: rf_get_munge_headers.c
+rf_get_transport.o: rf_get_transport.c
+rf_get_ugid.o: rf_get_ugid.c
+rf_lookup_hostlist.o: rf_lookup_hostlist.c
+rf_queue_add.o: rf_queue_add.c
+rf_self_action.o: rf_self_action.c
+rf_set_ugid.o: rf_set_ugid.c
+
+accept.o accept.so: accept.c accept.h
+dnslookup.o dnslookup.so: dnslookup.c dnslookup.h
+ipliteral.o ipliteral.so: ipliteral.c ipliteral.h
+iplookup.o iplookup.so: iplookup.c iplookup.h
+manualroute.o manualroute.so: manualroute.c manualroute.h
+queryprogram.o queryprogram.so: queryprogram.c queryprogram.h
+redirect.o redirect.so: redirect.c redirect.h
# End
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER;
}
+
+
+# ifdef DYNLOOKUP
+# define accept_router_info _router_info
+# endif
+
+router_info accept_router_info =
+{
+.drinfo = {
+ .driver_name = US"accept",
+ .options = accept_router_options,
+ .options_count = &accept_router_options_count,
+ .options_block = &accept_router_option_defaults,
+ .options_len = sizeof(accept_router_options_block),
+ .init = accept_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = accept_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = ri_yestransport
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_ACCEPT*/
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER;
}
+
+
+
+# ifdef DYNLOOKUP
+# define dnslookup_router_info _router_info
+# endif
+
+router_info dnslookup_router_info =
+{
+.drinfo = {
+ .driver_name = US"dnslookup",
+ .options = dnslookup_router_options,
+ .options_count = &dnslookup_router_options_count,
+ .options_block = &dnslookup_router_option_defaults,
+ .options_len = sizeof(dnslookup_router_options_block),
+ .init = dnslookup_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = dnslookup_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = ri_yestransport
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_DNSLOOKUP*/
/* End of routers/dnslookup.c */
OK : DEFER;
}
+
+
+# ifdef DYNLOOKUP
+# define ipliteral_router_info _router_info
+# endif
+
+router_info ipliteral_router_info =
+{
+.drinfo = {
+ .driver_name = US"ipliteral",
+ .options = ipliteral_router_options,
+ .options_count = &ipliteral_router_options_count,
+ .options_block = &ipliteral_router_option_defaults,
+ .options_len = sizeof(ipliteral_router_options_block),
+ .init = ipliteral_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = ipliteral_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = ri_yestransport
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_IPLITERAL*/
/* End of routers/ipliteral.c */
return OK;
}
+
+
+# ifdef DYNLOOKUP
+# define iplookup_router_info _router_info
+# endif
+
+router_info iplookup_router_info =
+{
+.drinfo = {
+ .driver_name = US"iplookup",
+ .options = iplookup_router_options,
+ .options_count = &iplookup_router_options_count,
+ .options_block = &iplookup_router_option_defaults,
+ .options_len = sizeof(iplookup_router_options_block),
+ .init = iplookup_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = iplookup_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = ri_notransport
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_IPLOOKUP*/
/* End of routers/iplookup.c */
return OK;
}
+
+
+
+# ifdef DYNLOOKUP
+# define manualroute_router_info _router_info
+# endif
+
+router_info manualroute_router_info =
+{
+.drinfo = {
+ .driver_name = US"manualroute",
+ .options = manualroute_router_options,
+ .options_count = &manualroute_router_options_count,
+ .options_block = &manualroute_router_option_defaults,
+ .options_len = sizeof(manualroute_router_options_block),
+ .init = manualroute_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = manualroute_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = 0
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_MANUALROUTE*/
/* End of routers/manualroute.c */
return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER;
}
+
+
+# ifdef DYNLOOKUP
+# define queryprogram_router_info _router_info
+# endif
+
+router_info queryprogram_router_info =
+{
+.drinfo = {
+ .driver_name = US"queryprogram",
+ .options = queryprogram_router_options,
+ .options_count = &queryprogram_router_options_count,
+ .options_block = &queryprogram_router_option_defaults,
+ .options_len = sizeof(queryprogram_router_options_block),
+ .init = queryprogram_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = queryprogram_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = 0
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_QUERYPROGRAM*/
/* End of routers/queryprogram.c */
return yield;
}
+
+
+# ifdef DYNLOOKUP
+# define redirect_router_info _router_info
+# endif
+
+router_info redirect_router_info =
+{
+.drinfo = {
+ .driver_name = US"redirect",
+ .options = redirect_router_options,
+ .options_count = &redirect_router_options_count,
+ .options_block = &redirect_router_option_defaults,
+ .options_len = sizeof(redirect_router_options_block),
+ .init = redirect_router_init,
+# ifdef DYNLOOKUP
+ .dyn_magic = ROUTER_MAGIC,
+# endif
+ },
+.code = redirect_router_entry,
+.tidyup = NULL, /* no tidyup entry */
+.ri_flags = ri_notransport
+};
+
#endif /*!MACRO_PREDEF*/
#endif /*ROUTER_REDIRECT*/
/* End of routers/redirect.c */
} driver_instance;
typedef struct driver_info {
+ struct driver_info * next;
uschar *driver_name; /* Name of driver */
optionlist *options; /* Table of private options names */
int options_len; /* Length of same in bytes */
void (*init)( /* Initialization entry point */
struct driver_instance *);
+ uint dyn_magic; /* Magic num if dynamic, else zero */
} driver_info;
+/* Values for dyn_magic. Encode types and api version. */
+#define ROUTER_MAGIC 0x52544d31 /* RTM1 */
+#define TRANSPORT_MAGIC 0x54504d31 /* TPM1 */
+#define AUTH_MAGIC 0x65554d31 /* AUM1 */
+
+typedef struct {
+ uint magic;
+ uschar * class;
+} driver_magics;
+
/* Structure for holding information about the configured transports. Some
of the generally accessible options are set from the configuration file; others
options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
-for (transport_info * ti= transports_available; ti->drinfo.driver_name[0]; ti++)
+//for (transport_info * ti= transports_available; ti->drinfo.driver_name[0]; ti++)
+for (driver_info * di= (driver_info *)transports_available_newlist; di; di = di->next)
{
- spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", ti->drinfo.driver_name);
+ spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", di->driver_name);
builtin_macro_create(buf);
- options_from_list(ti->drinfo.options, (unsigned)*ti->drinfo.options_count,
- US"TRANSPORT", ti->drinfo.driver_name);
+ options_from_list(di->options, (unsigned)*di->options_count,
+ US"TRANSPORT", di->driver_name);
}
}
void
transport_init(void)
{
-readconf_driver_init(US"transport",
- (driver_instance **)(&transports), /* chain anchor */
- (driver_info *)transports_available, /* available drivers */
+for (transport_info * tblent = transports_available_oldarray;
+ *tblent->drinfo.driver_name; tblent++)
+ {
+ driver_info * listent = store_get(sizeof(transport_info), tblent);
+ memcpy(listent, tblent, sizeof(transport_info));
+ listent->next = (driver_info *)transports_available_newlist;
+ transports_available_newlist = (transport_info *)listent;
+ }
+
+readconf_driver_init((driver_instance **)&transports, /* chain anchor */
+ (driver_info **)&transports_available_newlist, /* available drivers */
sizeof(transport_info), /* size of info block */
&transport_defaults, /* default values for generic options */
sizeof(transport_instance), /* size of instance block */
optionlist_transports, /* generic options */
- optionlist_transports_size);
+ optionlist_transports_size,
+ US"transport");
/* Now scan the configured transports and check inconsistencies. A shadow
transport is permitted only for local transports. */
tls_advertise_hosts =
keep_environment =
+begin routers
+
# End
| Authenticators:
| Lookups(?:\(built-in\))?:
| Support\ for:
- | Routers:
+ | Routers\ \((?:built-in|dynamic)\):
| Transports:
| Malware:
| log\ selectors\ =
# drop lookups
next if /^$time_pid?(?: Lookups\ \((?:built-in|dynamic)\):
- |Loaded\ "[^.]+\.so"\ \(\d+\ lookup\ types\)
+ | Loaded\ "[^.]+\.so"\ \(\d+\ lookup\ types\)
| Loading\ lookup\ modules\ from
| Loaded\ \d+\ lookup\ modules
| Total\ \d+\ lookups)/x;
+ # drop loads of dyn-module drivers
+ next if /^$time_pid?(?:Loading\ \w+\ (?:router|transport|auth)\ driver\ from
+ | Loaded\ \w+\ (?:router|transport|auth)$)/x;
+
# drop compiler information
next if /^$time_pid?Compiler:/;
%parm_authenticators = @temp;
}
- elsif (/^Routers: (.*)/)
+ elsif (/^Routers \((?:built-in|dynamic)\): ?(.*)/)
{
print;
@temp = split /(\s+)/, $1;
push(@temp, ' ');
- %parm_routers = @temp;
+ my %temp_routers= @temp;
+ @parm_routers{keys %temp_routers} = values %temp_routers;
}
# Some transports have options, e.g. appendfile/maildir. For those, ensure
($parm_exim_dir) = $parm_exim =~ m?^(.*)/exim?;
-while (my $file = glob("$parm_exim_dir/lookups/*.so")) {
+while (my $file = glob("$parm_exim_dir/dynmodules/*.so")) {
my $base = basename($file);
cp("$file", "eximdir/");
system("sudo chmod 755 eximdir/$base");