Merge branch 'router_dynamic_modules'
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 14 Aug 2024 10:19:50 +0000 (11:19 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 14 Aug 2024 10:19:50 +0000 (11:19 +0100)
27 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/OS/Makefile-Base
src/scripts/Configure-Makefile
src/scripts/MakeLinks
src/scripts/routers-Makefile [new file with mode: 0755]
src/src/EDITME
src/src/drtables.c
src/src/exim.c
src/src/functions.h
src/src/globals.h
src/src/lookups/Makefile
src/src/lookups/cdb.c
src/src/readconf.c
src/src/route.c
src/src/routers/Makefile
src/src/routers/accept.c
src/src/routers/dnslookup.c
src/src/routers/ipliteral.c
src/src/routers/iplookup.c
src/src/routers/manualroute.c
src/src/routers/queryprogram.c
src/src/routers/redirect.c
src/src/structs.h
src/src/transport.c
test/confs/0000
test/runtest

index 94b2b0cd20040dbe36bd321d1395a620b06bafd9..84597da830f56e7f0286787f13ce71607fcc0726 100644 (file)
@@ -2069,8 +2069,9 @@ withdrawn.
 
 
 
-.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
@@ -2081,6 +2082,12 @@ library dependencies without requiring all systems to install all of those
 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
index d69c1af85880bed00f5fee783ae37b14072b86bd..bb7f2290e201a4c4683873c354b7d5a43b18b3a4 100644 (file)
@@ -14,7 +14,8 @@ Version 4.98
 
  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
 ------------
index f494249bfcea86328bfe4eb5084033a068ed075d..d45524561286e69e3f603857d7971f5a398ff29e 100644 (file)
@@ -36,7 +36,7 @@ FE       = $(FULLECHO)
 # 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
@@ -245,7 +245,7 @@ macro.c: macro_predef
 
 .PHONY: all config utils \
        buildauths buildlookups buildpdkim buildrouters \
-        buildtransports checklocalmake clean
+        buildtransports dynmodules checklocalmake clean
 
 
 utils: $(EXIM_MONITOR) exicyclog exinext exiwhat \
@@ -943,6 +943,18 @@ $(MONBIN): $(HDRS)
 
 # 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
@@ -956,6 +968,7 @@ 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 " "
@@ -964,6 +977,7 @@ buildrouters: config
 
 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 " "
@@ -972,6 +986,7 @@ buildtransports: config
 
 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 " "
index 129f2a073ebb086db2f1ac6ee161763ecd0411b1..3b0528940ff311a0f73e6d2f86b04830f409006e 100755 (executable)
@@ -4,7 +4,7 @@
 # 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
 
 
@@ -291,6 +291,13 @@ rm -f $mftt
 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
index 355f4d6e9eeddc9d76cbc4208d312a9df60c0c85..f413c625edb11a1bd763a97089f372d4771d86e3 100755 (executable)
@@ -46,7 +46,8 @@ cd ..
 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 \
diff --git a/src/scripts/routers-Makefile b/src/scripts/routers-Makefile
new file mode 100755 (executable)
index 0000000..5bb6a78
--- /dev/null
@@ -0,0 +1,180 @@
+#! /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 :
index cf8afbd2658aa25cf33aee13ef331271a715006c..5e755692fd5b878abf14b4b2e067a630ea6f6960 100644 (file)
@@ -313,6 +313,15 @@ SPOOL_DIRECTORY=/var/spool/exim
 # 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
index 424c6197c3f2dacdc02add170ea0714209d41a0f..b514090966b7f2843dbf9ae14052ad9c9af83d5e 100644 (file)
@@ -61,7 +61,8 @@ set to NULL for those that are not compiled into the binary. */
 #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 */
 
@@ -229,34 +230,6 @@ exim binary. */
 
 #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
@@ -282,120 +255,11 @@ exim binary. */
 #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 = {
@@ -501,7 +365,7 @@ gstring *
 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");
 }
@@ -509,10 +373,57 @@ 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 *
@@ -671,8 +582,8 @@ void
 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
@@ -764,18 +675,23 @@ addlookupmodule(NULL, &testdb_lookup_module_info);
 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)))
index d86625f928bd081e78bcc93e74a48bf9fe86bd44..8eb602a171f96cab312c7e679f0ab9af46ca9714 100644 (file)
@@ -1382,7 +1382,8 @@ g = show_db_version(g);
 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);
 
index e13f8044e0ee09e05b313495eada5b14ad39d489..3253043ae29d1a8d287d42e875d926f96a26f627 100644 (file)
@@ -107,6 +107,8 @@ extern uschar *acl_standalone_setvar(const uschar *, BOOL);
 
 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
@@ -423,8 +425,8 @@ extern int     rda_interpret(redirect_block *, int, const uschar *,
                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 *);
index 8e75f7f93e8a3135e57e0982db44862f13d6ad64..6bca06c00999ade79137a7f6f424fbf5a7527bf9 100644 (file)
@@ -374,7 +374,8 @@ extern uschar *authenticated_sender;   /* From AUTH on MAIL */
 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 */
@@ -946,7 +947,7 @@ extern int     rfc1413_query_timeout;  /* Timeout on RFC 1413 calls */
 /* 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 */
@@ -1110,7 +1111,8 @@ extern int     transport_newlines;     /* Accurate count of number of newline ch
 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 */
 
index 19585bf31a3755f71f579ef1f6000845ec73be9c..12d9d88b4c7da9518f8a291d023817d97376bddf 100644 (file)
@@ -2,11 +2,11 @@
 # 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
 
@@ -30,47 +30,26 @@ lf_check_file.o: $(HDRS) lf_check_file.c  lf_functions.h
 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
index 696e520194cb736edfd3abe04e9d3e0e7e0dc5a5..a0f668b983275d8f19321668475184fe8db33c34 100644 (file)
@@ -482,7 +482,7 @@ lookup_info cdb_lookup_info = {
 };
 
 #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 };
index 231d3feb64f376da55cc9b63453a6f15f264b3af..57788afc39c28b561dbf5cdb7978e623a75df8fc 100644 (file)
@@ -435,9 +435,13 @@ uschar buf[EXIM_DRIVERNAME_MAX];
 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,
@@ -3695,6 +3699,18 @@ if (!nowarn && !keep_environment && environ && *environ)
 
 
 
+/* 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                 *
 *************************************************/
@@ -3707,34 +3723,103 @@ set by another incarnation of the same 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;
 }
 
 
@@ -3767,28 +3852,29 @@ driver_instance must map the first portions of all the _info and _instance
 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;
@@ -3875,7 +3961,7 @@ while ((buffer = get_config_line()))
         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
@@ -4243,14 +4329,24 @@ auths_init(void)
 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)
   {
@@ -4428,6 +4524,7 @@ while(next_section[0] != 0)
   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 (;;)
index b20e1ca0b95cb25d0e558e839eb17b6284d907c9..07f0a6b20d9635e23f58d474398be9f011e2a420 100644 (file)
@@ -159,12 +159,12 @@ uschar buf[64];
 
 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);
   }
 }
 
@@ -227,14 +227,59 @@ function. */
 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)
   {
index 8f2432d5eb58356b88db293364072b2eba60c399..d13a493e9d4f8b448f815242b9c9311f9615d2db 100644 (file)
@@ -2,42 +2,59 @@
 # 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
index 6cbde6decefbbbb92c3fb395268115f2e5ce53be..5b247131f5d02a90ba6c6f51c957af3a6b2cb3ab 100644 (file)
@@ -140,6 +140,30 @@ addr->prop.remove_headers = remove_headers;
 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*/
 
index 8a6f72d5d65f270824628598338cad8f0d25b93d..1520cc376930c656bced6ce468af6c8f115812cd 100644 (file)
@@ -475,6 +475,31 @@ addr->transport = rblock->transport;
 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 */
index 790ef15f0816c52e4f3a96dc7d30268ca4455bd4..54a776e9ad7eb0a04c51d695012976c42e630872 100644 (file)
@@ -201,6 +201,30 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
   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 */
index 26e9b7ce7c0f2cc97c1964e5443b4763d6ba27f8..464112bc0ce8ed12705035037829cd1a327a5df0 100644 (file)
@@ -417,6 +417,30 @@ if (rc != OK) return rc;
 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 */
index 05043a8147ae71a95afe79365270283906099e03..c24ae0e2c025df76174337f6d9cdbd2e99fd1a1c 100644 (file)
@@ -495,6 +495,31 @@ addr->transport = transport;
 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 */
index 82c3f2001568f1b4916a17b6277b0e871e462f9b..9433759125c383e641bc7117bebb678c6bd5d554 100644 (file)
@@ -534,6 +534,30 @@ addr->prop = addr_prop;
 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 */
index 936cfca14635a0fc1fbb80880f39471888c9e3e0..86278d818806823e460248f8d6732fefc0fa1ac8 100644 (file)
@@ -788,6 +788,30 @@ addr->next = *addr_succeed;
 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 */
index ee312a44efe6f4924c0c5caf2c4ec7ffa733280c..ffcd8a5dfe9b1ce597f87e6962d38f55b7ea8882 100644 (file)
@@ -141,6 +141,7 @@ typedef struct driver_instance {
 } driver_instance;
 
 typedef struct driver_info {
+  struct driver_info * next;
   uschar *driver_name;            /* Name of driver */
 
   optionlist *options;            /* Table of private options names */
@@ -149,8 +150,19 @@ typedef struct driver_info {
   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
index 3889a8529c3ab556d44cfaeaac0465c92a7169b1..e42625ce82e6b0051132e3cb01f9c3a18b5f6f97 100644 (file)
@@ -102,12 +102,13 @@ uschar buf[64];
 
 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);
   }
 }
 
@@ -145,14 +146,23 @@ the work. */
 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. */
index 12c91fda1d32423f76c921936118e9dc591fdcd9..795701bd778dd58830e19d68f17581a1df379254 100644 (file)
@@ -10,4 +10,6 @@ gecos_name = CALLER_NAME
 tls_advertise_hosts =
 keep_environment =
 
+begin routers
+
 # End
index b89960a8bb867570b754016cf7b34fb32b46f814..2922335511654bc68864ddb9a7efe6c3e48d5375 100755 (executable)
@@ -1163,7 +1163,7 @@ RESET_AFTER_EXTRA_LINE_READ:
                  | Authenticators:
                  | Lookups(?:\(built-in\))?:
                  | Support\ for:
-                 | Routers:
+                 | Routers\ \((?:built-in|dynamic)\):
                  | Transports:
                  | Malware:
                  | log\ selectors\ =
@@ -1298,11 +1298,15 @@ RESET_AFTER_EXTRA_LINE_READ:
 
     # 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:/;
 
@@ -3745,12 +3749,13 @@ while (<EXIMINFO>)
     %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
@@ -4138,7 +4143,7 @@ system("sudo cp eximdir/exim eximdir/exim_exim;" .
 
 ($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");