From: Jeremy Harris Date: Thu, 15 Aug 2024 13:53:22 +0000 (+0100) Subject: transport dynamic modules X-Git-Url: https://git.exim.org/exim.git/commitdiff_plain/f4db5740c56f3b29b11a796147086ec8848a7e90 transport dynamic modules --- diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 84597da83..9fbf7a2db 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -2072,6 +2072,7 @@ withdrawn. .section "Dynamically loaded module support" "SECTdynamicmodules" .cindex "lookup modules" .cindex "router modules" +.cindex "transport modules" .cindex "dynamic modules" .cindex ".so building" On some platforms, Exim supports not compiling all lookup types directly into @@ -2083,7 +2084,7 @@ dependencies. Most, but not all, lookup types can be built this way. .new -Similarly, router drivers can be built as external modules. +Similarly, router and transport drivers can be built as external modules. This permits a smaller exim binary, growing only as needed for the runtime cofiguration. .wen diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index bb7f2290e..be0f0c679 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -14,8 +14,8 @@ Version 4.98 3. Events smtp:fail:protocol and smtp:fail:syntax - 4. JSON lookup support, and all the router driver except manualroute, - can now be built as lodable modules + 4. JSON lookup support, all the router drivers except manualroute, and all the transport + drivers except smtp can now be built as lodable modules Version 4.98 ------------ diff --git a/src/scripts/Configure-Makefile b/src/scripts/Configure-Makefile index 3b0528940..20e686b51 100755 --- a/src/scripts/Configure-Makefile +++ b/src/scripts/Configure-Makefile @@ -10,6 +10,7 @@ LC_ALL=C export LC_ALL +set -e # First off, get the OS type, and check that there is a make file for it. @@ -291,12 +292,16 @@ 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= +while read class classdef names +do + cp ../src/$class/Makefile $class/Makefile.predynamic + CLASS=$class CLASSDEF=$classdef DRNAMES="$names" ../scripts/drivers-Makefile + mv $class/Makefile.postdynamic $class/Makefile + rm $class/Makefile.predynamic +done <<-END + routers ROUTER ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT + transports TRANSPORT APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP +END # 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, diff --git a/src/scripts/MakeLinks b/src/scripts/MakeLinks index f413c625e..998b73bf9 100755 --- a/src/scripts/MakeLinks +++ b/src/scripts/MakeLinks @@ -63,7 +63,8 @@ cd .. d="transports" mkdir $d cd $d -for f in README Makefile appendfile.h appendfile.c autoreply.h \ +# Makefile is generated +for f in README appendfile.h appendfile.c autoreply.h \ autoreply.c lmtp.h lmtp.c pipe.h pipe.c queuefile.c queuefile.h \ smtp.h smtp.c smtp_socks.c tf_maildir.c tf_maildir.h do diff --git a/src/scripts/drivers-Makefile b/src/scripts/drivers-Makefile new file mode 100755 index 000000000..0c3da19cb --- /dev/null +++ b/src/scripts/drivers-Makefile @@ -0,0 +1,176 @@ +#! /bin/sh + +# Copyright (c) The Exim Maintainers 1995 - 2024 +# SPDX-License-Identifier: GPL-2.0-or-later + +set -e +class=${CLASS:?} +classdef=${CLASSDEF:?} +drnames="${DRNAMES:?}" + +# We turn the configure-built build-$foo/$class/Makefile.predynamic into Makefile. +# This is used for router and transport drivers, called from scripts/Configure-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_DRIVER_MAKEFILE_ADJUSTED" ] +then + SHELL=/bin/sh + EXIM_DRIVER_MAKEFILE_ADJUSTED=yes + export EXIM_DRIVER_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=$class/Makefile.predynamic +target=$class/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 $class/Makefile for building dynamic modules" + enable_dynamic=yes +else + echo >&2 ">>> Creating $class/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="(${classdef}|EXPERIMENTAL)_${dyn_name}[ $tab]*=[ $tab]*2" + env | grep -E -q "^$re" + if [ $? -eq 0 ]; then return 0; fi + grep -E -q "^[ $tab]*$re" "$defs_source" +} + +want_at_all() { + local want_name="$1" + local re="(${classdef}|EXPERIMENTAL)_${want_name}[ $tab]*=[ $tab]*." + env | grep -E -q "^$re" + if [ $? -eq 0 ]; then return 0; fi + grep -E -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 "^${classdef}_${name}_PC" "$defs_source") +# if [ $? -eq 0 ]; then +# pkgconf=$(echo $pkgconf | sed 's/^.*= *//') +# echo "${classdef}_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)" +# echo "${classdef}_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)" +# else +# grep "^${classdef}_${name}_" "$defs_source" +# echo "${classdef}_${mod_name}_INCLUDE = \$(${classdef}_${name}_INCLUDE)" +# echo "${classdef}_${mod_name}_LIBS = \$(${classdef}_${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 $drnames +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 : diff --git a/src/scripts/routers-Makefile b/src/scripts/routers-Makefile deleted file mode 100755 index 5bb6a78d8..000000000 --- a/src/scripts/routers-Makefile +++ /dev/null @@ -1,180 +0,0 @@ -#! /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 : diff --git a/src/src/EDITME b/src/src/EDITME index 5e755692f..820793032 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -344,6 +344,15 @@ ROUTER_REDIRECT=yes # 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. +# The smtp transport cannot be built as a module. TRANSPORT_APPENDFILE=yes TRANSPORT_AUTOREPLY=yes diff --git a/src/src/drtables.c b/src/src/drtables.c index b51409096..026f2ff97 100644 --- a/src/src/drtables.c +++ b/src/src/drtables.c @@ -230,134 +230,11 @@ exim binary. */ #include "routers/rf_functions.h" -#ifdef TRANSPORT_APPENDFILE -# include "transports/appendfile.h" -#endif - -#ifdef TRANSPORT_AUTOREPLY -# include "transports/autoreply.h" -#endif - -#ifdef TRANSPORT_LMTP -# include "transports/lmtp.h" -#endif - -#ifdef TRANSPORT_PIPE -# include "transports/pipe.h" -#endif - -#ifdef EXPERIMENTAL_QUEUEFILE -# include "transports/queuefile.h" -#endif - -#ifdef TRANSPORT_SMTP -# include "transports/smtp.h" -#endif - router_info * routers_available = NULL; +transport_info * transports_available = NULL; -transport_info * transports_available_newlist = NULL; -transport_info transports_available_oldarray[] = { -#ifdef TRANSPORT_APPENDFILE - { - .drinfo = { - .driver_name = US"appendfile", - .options = appendfile_transport_options, - .options_count = &appendfile_transport_options_count, - .options_block = &appendfile_transport_option_defaults, /* private options defaults */ - .options_len = sizeof(appendfile_transport_options_block), - .init = appendfile_transport_init, - }, - .code = appendfile_transport_entry, - .tidyup = NULL, - .closedown = NULL, - .local = TRUE - }, -#endif -#ifdef TRANSPORT_AUTOREPLY - { - .drinfo = { - .driver_name = US"autoreply", - .options = autoreply_transport_options, - .options_count = &autoreply_transport_options_count, - .options_block = &autoreply_transport_option_defaults, - .options_len = sizeof(autoreply_transport_options_block), - .init = autoreply_transport_init, - }, - .code = autoreply_transport_entry, - .tidyup = NULL, - .closedown = NULL, - .local = TRUE - }, -#endif -#ifdef TRANSPORT_LMTP - { - .drinfo = { - .driver_name = US"lmtp", - .options = lmtp_transport_options, - .options_count = &lmtp_transport_options_count, - .options_block = &lmtp_transport_option_defaults, - .options_len = sizeof(lmtp_transport_options_block), - .init = lmtp_transport_init, - }, - .code = lmtp_transport_entry, - .tidyup = NULL, - .closedown = NULL, - .local = TRUE - }, -#endif -#ifdef TRANSPORT_PIPE - { - .drinfo = { - .driver_name = US"pipe", - .options = pipe_transport_options, - .options_count = &pipe_transport_options_count, - .options_block = &pipe_transport_option_defaults, - .options_len = sizeof(pipe_transport_options_block), - .init = pipe_transport_init, - }, - .code = pipe_transport_entry, - .tidyup = NULL, - .closedown = NULL, - .local = TRUE - }, -#endif -#ifdef EXPERIMENTAL_QUEUEFILE - { - .drinfo = { - .driver_name = US"queuefile", - .options = queuefile_transport_options, - .options_count = &queuefile_transport_options_count, - .options_block = &queuefile_transport_option_defaults, - .options_len = sizeof(queuefile_transport_options_block), - .init = queuefile_transport_init, - }, - .code = queuefile_transport_entry, - .tidyup = NULL, - .closedown = NULL, - .local = TRUE - }, -#endif -#ifdef TRANSPORT_SMTP - { - .drinfo = { - .driver_name = US"smtp", - .options = smtp_transport_options, - .options_count = &smtp_transport_options_count, - .options_block = &smtp_transport_option_defaults, - .options_len = sizeof(smtp_transport_options_block), - .init = smtp_transport_init, - }, - .code = smtp_transport_entry, - .tidyup = NULL, - .closedown = smtp_transport_closedown, - .local = FALSE - }, -#endif - { .drinfo = { .driver_name = US"" }} -}; #ifndef MACRO_PREDEF @@ -429,35 +306,69 @@ return g; gstring * transport_show_supported(gstring * g) { -g = string_cat(g, US"Transports:"); -#ifdef TRANSPORT_APPENDFILE - g = string_cat(g, US" appendfile"); - #ifdef SUPPORT_MAILDIR - g = string_cat(g, US"/maildir"); /* damn these subclasses */ - #endif - #ifdef SUPPORT_MAILSTORE - g = string_cat(g, US"/mailstore"); - #endif - #ifdef SUPPORT_MBX - g = string_cat(g, US"/mbx"); - #endif -#endif -#ifdef TRANSPORT_AUTOREPLY - g = string_cat(g, US" autoreply"); -#endif -#ifdef TRANSPORT_LMTP - g = string_cat(g, US" lmtp"); -#endif -#ifdef TRANSPORT_PIPE - g = string_cat(g, US" pipe"); -#endif -#ifdef EXPERIMENTAL_QUEUEFILE - g = string_cat(g, US" queuefile"); -#endif -#ifdef TRANSPORT_SMTP - g = string_cat(g, US" smtp"); +uschar * b = US"" /* static-build transportnames */ +#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2 + " appendfile" +# ifdef SUPPORT_MAILDIR + "/maildir" +# endif +# ifdef SUPPORT_MAILSTORE + "/mailstore" +# endif +# ifdef SUPPORT_MBX + "/mbx" +# endif +#endif +#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2 + " autoreply" +#endif +#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2 + " lmtp" +#endif +#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2 + " pipe" +#endif +#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2 + " queuefile" +#endif +#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2 + " smtp" #endif -return string_cat(g, US"\n"); + ; + +uschar * d = US"" /* dynamic-module transportnames */ +#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2 + " appendfile" +# ifdef SUPPORT_MAILDIR + "/maildir" +# endif +# ifdef SUPPORT_MAILSTORE + "/mailstore" +# endif +# ifdef SUPPORT_MBX + "/mbx" +# endif +#endif +#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2 + " autoreply" +#endif +#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2 + " lmtp" +#endif +#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2 + " pipe" +#endif +#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2 + " queuefile" +#endif +#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2 + " smtp" +#endif + ; + +if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b); +if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d); +return g; } diff --git a/src/src/globals.h b/src/src/globals.h index 6bca06c00..7fc888f5b 100644 --- a/src/src/globals.h +++ b/src/src/globals.h @@ -1111,10 +1111,9 @@ 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_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 */ +extern transport_info * transports_available; /* Listof available transports */ +extern transport_instance *transports; /* Chain of instantiated transports */ +extern transport_instance transport_defaults; /* Default values */ extern int transport_write_timeout;/* Set to time out individual writes */ diff --git a/src/src/route.c b/src/src/route.c index 07f0a6b20..293d21c50 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -227,7 +227,6 @@ function. */ void route_init(void) { - int old_pool = store_pool; store_pool = POOL_PERM; { diff --git a/src/src/routers/Makefile b/src/src/routers/Makefile index d13a493e9..8ff3d81ab 100644 --- a/src/src/routers/Makefile +++ b/src/src/routers/Makefile @@ -7,7 +7,7 @@ # 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. +# interpolated below. This is done by scripts/drivers-Makefile. # MAGIC-TAG-MODS-OBJ-RULES-GO-HERE diff --git a/src/src/transport.c b/src/src/transport.c index e42625ce8..063fda361 100644 --- a/src/src/transport.c +++ b/src/src/transport.c @@ -102,8 +102,7 @@ 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 (driver_info * di= (driver_info *)transports_available_newlist; di; di = di->next) +for (driver_info * di= (driver_info *)transports_available; di; di = di->next) { spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", di->driver_name); builtin_macro_create(buf); @@ -146,21 +145,51 @@ the work. */ void transport_init(void) { -for (transport_info * tblent = transports_available_oldarray; - *tblent->drinfo.driver_name; tblent++) +int old_pool = store_pool; +store_pool = POOL_PERM; { - 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; + driver_info ** anchor = (driver_info **) &transports_available; + extern transport_info appendfile_transport_info; + extern transport_info autoreply_transport_info; + extern transport_info lmtp_transport_info; + extern transport_info pipe_transport_info; + extern transport_info queuefile_transport_info; + extern transport_info smtp_transport_info; + + /* Add the transport drivers that are built for static linkage to the + list of availables. */ + +#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2 + add_driver_info(anchor, &appendfile_transport_info.drinfo, sizeof(transport_info)); +#endif +#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2 + add_driver_info(anchor, &autoreply_transport_info.drinfo, sizeof(transport_info)); +#endif +#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2 + add_driver_info(anchor, &lmtp_transport_info.drinfo, sizeof(transport_info)); +#endif +#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2 + add_driver_info(anchor, &pipe_transport_info.drinfo, sizeof(transport_info)); +#endif +#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2 + add_driver_info(anchor, &queuefile_transport_info.drinfo, sizeof(transport_info)); +#endif +#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2 + add_driver_info(anchor, &smtp_transport_info.drinfo, sizeof(transport_info)); +#endif } +store_pool = old_pool; + +/* Read the config file "transports" section, creating a transportsinstance list. +For any yet-undiscovered driver, check for a loadable module and add it to +those available. */ 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 */ + (driver_info **)&transports_available, /* 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, US"transport"); diff --git a/src/src/transports/Makefile b/src/src/transports/Makefile index 4eea141ec..8f759ecf0 100644 --- a/src/src/transports/Makefile +++ b/src/src/transports/Makefile @@ -1,8 +1,16 @@ # Make file for building a library containing all the available transports and # calling it transports.a. This is called from the main make file, after cd'ing # to the transports subdirectory. +# +# Copyright (c) The Exim Maintainers 2021 - 2024 -OBJ = appendfile.o autoreply.o lmtp.o pipe.o queuefile.o smtp.o smtp_socks.o tf_maildir.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/drivers-Makefile. + +# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE + +all: transports.a $(MODS) transports.a: $(OBJ) @$(RM_COMMAND) -f transports.a @@ -10,18 +18,40 @@ transports.a: $(OBJ) @$(AR) transports.a $(OBJ) $(RANLIB) $@ -.SUFFIXES: .o .c +.SUFFIXES: .o .c .so .c.o:; @echo "$(CC) $*.c" $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c -appendfile.o: $(HDRS) appendfile.c appendfile.h tf_maildir.h -autoreply.o: $(HDRS) autoreply.c autoreply.h -lmtp.o: $(HDRS) lmtp.c lmtp.h -pipe.o: $(HDRS) pipe.c pipe.h -queuefile.o: $(HDRS) queuefile.c queuefile.h -smtp.o: $(HDRS) smtp.c smtp.h -smtp_socks.o: $(HDRS) smtp_socks.c smtp.h +.c.so:; @echo "$(CC) -shared $*.c" + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@ + + +$(OBJ) $(MOD): $(HDRS) + +autoreply.o autoreply.so: autoreply.c autoreply.h +lmtp.o lmtp.so: lmtp.c lmtp.h +pipe.o pipe.so: pipe.c pipe.h +queuefile.o queuefile.so: queuefile.c queuefile.h + + +# These ones depend on more than one .c source + +appendfile.o: appendfile.c appendfile.h tf_maildir.c tf_maildir.h + @echo "$(CC) appendfile.c tf_maildir.c" + $(FE)$(CC) $(CFLAGS) $(INCLUDE) appendfile.c tf_maildir.c -r -o $@ + +appendfile.so: appendfile.c appendfile.h tf_maildir.c tf_maildir.h + @echo "$(CC) -shared appendfile.c tf_maildir.c" + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \ + appendfile.c tf_maildir.c -o $@ + +smtp.o: smtp.c smtp_socks.c smtp.h + @echo "$(CC) smtp.c smtp_socks.c" + $(FE)$(CC) $(CFLAGS) $(INCLUDE) smtp.c smtp_socks.c -r -o $@ -tf_maildir.o: $(HDRS) tf_maildir.c tf_maildir.h appendfile.h +smtp.so: smtp.c smtp_socks.c smtp.h + @echo "$(CC) -shared smtp.c smtp_socks.c" + $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \ + smtp.c smtp_socks.c -o $@ # End diff --git a/src/src/transports/appendfile.c b/src/src/transports/appendfile.c index 14ef13c97..08a59543c 100644 --- a/src/src/transports/appendfile.c +++ b/src/src/transports/appendfile.c @@ -3319,6 +3319,31 @@ ret_panic: return FALSE; } + + + +# ifdef DYNLOOKUP +# define appendfile_transport_info _transport_info +# endif + +transport_info appendfile_transport_info = { +.drinfo = { + .driver_name = US"appendfile", + .options = appendfile_transport_options, + .options_count = &appendfile_transport_options_count, + .options_block = &appendfile_transport_option_defaults, /* private options defaults */ + .options_len = sizeof(appendfile_transport_options_block), + .init = appendfile_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = appendfile_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ #endif /*TRANSPORT_APPENDFILE*/ /* End of transport/appendfile.c */ diff --git a/src/src/transports/autoreply.c b/src/src/transports/autoreply.c index a6080695e..9223bc791 100644 --- a/src/src/transports/autoreply.c +++ b/src/src/transports/autoreply.c @@ -806,6 +806,31 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", trname); return FALSE; } + + + +# ifdef DYNLOOKUP +# define autoreply_transport_info _transport_info +# endif + +transport_info autoreply_transport_info = { +.drinfo = { + .driver_name = US"autoreply", + .options = autoreply_transport_options, + .options_count = &autoreply_transport_options_count, + .options_block = &autoreply_transport_option_defaults, + .options_len = sizeof(autoreply_transport_options_block), + .init = autoreply_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = autoreply_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ #endif /*TRANSPORT_AUTOREPOL*/ /* End of transport/autoreply.c */ diff --git a/src/src/transports/lmtp.c b/src/src/transports/lmtp.c index ae9295292..1bff274c1 100644 --- a/src/src/transports/lmtp.c +++ b/src/src/transports/lmtp.c @@ -808,6 +808,31 @@ MINUS_N: return FALSE; } + + + +# ifdef DYNLOOKUP +# define lmtp_transport_info _transport_info +# endif + +transport_info lmtp_transport_info = { +.drinfo = { + .driver_name = US"lmtp", + .options = lmtp_transport_options, + .options_count = &lmtp_transport_options_count, + .options_block = &lmtp_transport_option_defaults, + .options_len = sizeof(lmtp_transport_options_block), + .init = lmtp_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = lmtp_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ #endif /*TRANSPORT_LMTP*/ /* End of transport/lmtp.c */ diff --git a/src/src/transports/pipe.c b/src/src/transports/pipe.c index 1b90c4314..b765eeae5 100644 --- a/src/src/transports/pipe.c +++ b/src/src/transports/pipe.c @@ -1128,6 +1128,31 @@ if (addr->transport_return != OK) return FALSE; } + + + +# ifdef DYNLOOKUP +# define pipe_transport_info _transport_info +# endif + +transport_info pipe_transport_info = { +.drinfo = { + .driver_name = US"pipe", + .options = pipe_transport_options, + .options_count = &pipe_transport_options_count, + .options_block = &pipe_transport_option_defaults, + .options_len = sizeof(pipe_transport_options_block), + .init = pipe_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = pipe_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ #endif /*TRASPORT_PIPE*/ /* End of transport/pipe.c */ diff --git a/src/src/transports/queuefile.c b/src/src/transports/queuefile.c index 2c35b3145..64031e55d 100644 --- a/src/src/transports/queuefile.c +++ b/src/src/transports/queuefile.c @@ -285,5 +285,30 @@ put in the first address of a batch. */ return FALSE; } + + + +# ifdef DYNLOOKUP +# define queuefile_transport_info _transport_info +# endif + +transport_info queuefile_transport_info = { +.drinfo = { + .driver_name = US"queuefile", + .options = queuefile_transport_options, + .options_count = &queuefile_transport_options_count, + .options_block = &queuefile_transport_option_defaults, + .options_len = sizeof(queuefile_transport_options_block), + .init = queuefile_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = queuefile_transport_entry, +.tidyup = NULL, +.closedown = NULL, +.local = TRUE +}; + #endif /*!MACRO_PREDEF*/ #endif /*EXPERIMENTAL_QUEUEFILE*/ diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index 25858d982..d25a2b1f6 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -6230,6 +6230,31 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", trname); return TRUE; /* Each address has its status */ } + + + +# ifdef DYNLOOKUP +# define smtp_transport_info _transport_info +# endif + +transport_info smtp_transport_info = { +.drinfo = { + .driver_name = US"smtp", + .options = smtp_transport_options, + .options_count = &smtp_transport_options_count, + .options_block = &smtp_transport_option_defaults, + .options_len = sizeof(smtp_transport_options_block), + .init = smtp_transport_init, +# ifdef DYNLOOKUP + .dyn_magic = TRANSPORT_MAGIC, +# endif + }, +.code = smtp_transport_entry, +.tidyup = NULL, +.closedown = smtp_transport_closedown, +.local = FALSE +}; + #endif /*!MACRO_PREDEF*/ /* vi: aw ai sw=2 */ diff --git a/test/confs/0000 b/test/confs/0000 index 795701bd7..5db8ac8cf 100644 --- a/test/confs/0000 +++ b/test/confs/0000 @@ -11,5 +11,6 @@ tls_advertise_hosts = keep_environment = begin routers +begin transports # End diff --git a/test/runtest b/test/runtest index 292233551..632672324 100755 --- a/test/runtest +++ b/test/runtest @@ -1164,7 +1164,7 @@ RESET_AFTER_EXTRA_LINE_READ: | Lookups(?:\(built-in\))?: | Support\ for: | Routers\ \((?:built-in|dynamic)\): - | Transports: + | Transports\ \((?:built-in|dynamic)\): | Malware: | log\ selectors\ = | cwd= @@ -3754,7 +3754,7 @@ while () print; @temp = split /(\s+)/, $1; push(@temp, ' '); - my %temp_routers= @temp; + my %temp_routers = @temp; @parm_routers{keys %temp_routers} = values %temp_routers; } @@ -3762,13 +3762,15 @@ while () # that the basic transport name is set, and then the name with each of the # options. - elsif (/^Transports: (.*)/) + elsif (/^Transports \((?:built-in|dynamic)\): (.*)/) { print; @temp = split /(\s+)/, $1; my($i,$k); push(@temp, ' '); - %parm_transports = @temp; + my %temp_transports = @temp; + @parm_transports{keys %temp_transports} = values %temp_transports; + foreach $k (keys %parm_transports) { if ($k =~ "/")