[exim-cvs] common driver structs for routers

Página Inicial
Delete this message
Reply to this message
Autor: Exim Git Commits Mailing List
Data:  
Para: exim-cvs
Assunto: [exim-cvs] common driver structs for routers
Gitweb: https://git.exim.org/exim.git/commitdiff/479274b860536bee4e54636557959389f71ad31b
Commit:     479274b860536bee4e54636557959389f71ad31b
Parent:     c5ccc6b8b3efcf06b724019643dbc4398ee6c71b
Author:     Jeremy Harris <jgh146exb@???>
AuthorDate: Fri Aug 9 23:12:24 2024 +0100
Committer:  Jeremy Harris <jgh146exb@???>
CommitDate: Sat Aug 10 15:29:43 2024 +0100


    common driver structs for routers
---
 src/src/deliver.c                       |  21 ++--
 src/src/drtables.c                      | 132 +++++++++++----------
 src/src/expand.c                        |  13 ++-
 src/src/functions.h                     |   8 +-
 src/src/globals.c                       |  66 +----------
 src/src/globals.h                       |   2 +-
 src/src/readconf.c                      | 195 +++++++++++++++++---------------
 src/src/route.c                         | 166 ++++++++++++++-------------
 src/src/routers/accept.c                |  10 +-
 src/src/routers/accept.h                |   2 +-
 src/src/routers/dnslookup.c             |  31 +++--
 src/src/routers/dnslookup.h             |   2 +-
 src/src/routers/ipliteral.c             |  10 +-
 src/src/routers/ipliteral.h             |   2 +-
 src/src/routers/manualroute.c           |  28 ++---
 src/src/routers/manualroute.h           |   2 +-
 src/src/routers/queryprogram.c          |  44 +++----
 src/src/routers/queryprogram.h          |   2 +-
 src/src/routers/redirect.c              |  54 ++++-----
 src/src/routers/redirect.h              |   2 +-
 src/src/routers/rf_get_errors_address.c |   2 +-
 src/src/routers/rf_get_munge_headers.c  |   4 +-
 src/src/routers/rf_get_ugid.c           |  22 ++--
 src/src/routers/rf_lookup_hostlist.c    |   4 +-
 src/src/structs.h                       |  28 ++---
 src/src/transports/smtp.c               |   5 +-
 src/src/verify.c                        |   2 +-
 27 files changed, 417 insertions(+), 442 deletions(-)


diff --git a/src/src/deliver.c b/src/src/deliver.c
index 67ba505d1..a4ec5f798 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -903,10 +903,11 @@ const uschar * save_domain = deliver_domain;
 const uschar * save_local =  deliver_localpart;
 const uschar * save_host = deliver_host;
 const uschar * save_address = deliver_host_address;
-uschar * save_rn = router_name, * save_tn = transport_name;
+const uschar * save_rn = router_name;
+uschar * save_tn = transport_name;
 const int      save_port =   deliver_host_port;


-router_name =    addr->router ? addr->router->name : NULL;
+router_name =    addr->router ? addr->router->drinst.name : NULL;
 deliver_domain = addr->domain;
 deliver_localpart = addr->local_part;
 deliver_host =   addr->host_used ? addr->host_used->name : NULL;
@@ -1177,7 +1178,7 @@ if (msg)


/* For a delivery from a system filter, there may not be a router */
if (addr->router)
- g = string_append(g, 2, US" R=", addr->router->name);
+ g = string_append(g, 2, US" R=", addr->router->drinst.name);

g = string_append(g, 2, US" T=", addr->transport->name);

@@ -1329,7 +1330,7 @@ so nothing has been done at all, both variables contain null strings. */
 if (driver_name)
   {
   if (driver_kind[1] == 't' && addr->router)
-    g = string_append(g, 2, US" R=", addr->router->name);
+    g = string_append(g, 2, US" R=", addr->router->drinst.name);
   g = string_fmt_append(g, " %c=%s", toupper(driver_kind[1]), driver_name);
   }
 else if (driver_kind)
@@ -1406,7 +1407,7 @@ if (used_return_path && LOGGING(return_path_on_delivery))
   g = string_append(g, 3, US" P=<", used_return_path, US">");


if (addr->router)
- g = string_append(g, 2, US" R=", addr->router->name);
+ g = string_append(g, 2, US" R=", addr->router->drinst.name);
if (addr->transport)
g = string_append(g, 2, US" T=", addr->transport->name);

@@ -1487,7 +1488,7 @@ else if (driver_type == EXIM_DTYPE_ROUTER)
   {
   if (addr->router)
     {
-    driver_name = addr->router->name;
+    driver_name = addr->router->drinst.name;
     driver_kind = US" router";
     f.disable_logging = addr->router->disable_logging;
     }
@@ -2377,7 +2378,7 @@ if ((pid = exim_fork(US"delivery-local")) == 0)
     /* Setting these globals in the subprocess means we need never clear them */


     transport_name = tp->name;
-    if (addr->router) router_name = addr->router->name;
+    if (addr->router) router_name = addr->router->drinst.name;
     driver_srcfile = tp->srcfile;
     driver_srcline = tp->srcline;


@@ -2742,7 +2743,7 @@ while (addr_local)
     logflags |= LOG_PANIC;
     f.disable_logging = FALSE;  /* Jic */
     addr->message = addr->router
-      ? string_sprintf("No transport set by %s router", addr->router->name)
+      ? string_sprintf("No transport set by %s router", addr->router->drinst.name)
       : US"No transport set by system filter";
     post_process_one(addr, DEFER, logflags, EXIM_DTYPE_TRANSPORT, 0);
     continue;
@@ -4818,7 +4819,7 @@ do_remote_deliveries par_reduce par_wait par_read_pipe
     /* Setting these globals in the subprocess means we need never clear them */


     transport_name = tp->name;
-    if (addr->router) router_name = addr->router->name;
+    if (addr->router) router_name = addr->router->drinst.name;
     driver_srcfile = tp->srcfile;
     driver_srcline = tp->srcline;


@@ -6459,7 +6460,7 @@ for (const address_item * a = addr_succeed; a; a = a->next)
       "DSN: envid: %s  ret: %d\n"
       "DSN: Final recipient: %s\n"
       "DSN: Remote SMTP server supports DSN: %d\n",
-      a->router ? a->router->name : US"(unknown)",
+      a->router ? a->router->drinst.name : US"(unknown)",
       a->address,
       sender_address,
       a->dsn_orcpt ? a->dsn_orcpt : US"NULL",
diff --git a/src/src/drtables.c b/src/src/drtables.c
index 9dd369a43..6f3cffe1e 100644
--- a/src/src/drtables.c
+++ b/src/src/drtables.c
@@ -212,55 +212,55 @@ exim binary. */
 #include "routers/rf_functions.h"


#ifdef ROUTER_ACCEPT
-#include "routers/accept.h"
+# include "routers/accept.h"
#endif

#ifdef ROUTER_DNSLOOKUP
-#include "routers/dnslookup.h"
+# include "routers/dnslookup.h"
#endif

#ifdef ROUTER_MANUALROUTE
-#include "routers/manualroute.h"
+# include "routers/manualroute.h"
#endif

#ifdef ROUTER_IPLITERAL
-#include "routers/ipliteral.h"
+# include "routers/ipliteral.h"
#endif

#ifdef ROUTER_IPLOOKUP
-#include "routers/iplookup.h"
+# include "routers/iplookup.h"
#endif

#ifdef ROUTER_QUERYPROGRAM
-#include "routers/queryprogram.h"
+# include "routers/queryprogram.h"
#endif

#ifdef ROUTER_REDIRECT
-#include "routers/redirect.h"
+# include "routers/redirect.h"
#endif

#ifdef TRANSPORT_APPENDFILE
-#include "transports/appendfile.h"
+# include "transports/appendfile.h"
#endif

#ifdef TRANSPORT_AUTOREPLY
-#include "transports/autoreply.h"
+# include "transports/autoreply.h"
#endif

#ifdef TRANSPORT_LMTP
-#include "transports/lmtp.h"
+# include "transports/lmtp.h"
#endif

#ifdef TRANSPORT_PIPE
-#include "transports/pipe.h"
+# include "transports/pipe.h"
#endif

#ifdef EXPERIMENTAL_QUEUEFILE
-#include "transports/queuefile.h"
+# include "transports/queuefile.h"
#endif

#ifdef TRANSPORT_SMTP
-#include "transports/smtp.h"
+# include "transports/smtp.h"
#endif


@@ -269,12 +269,14 @@ exim binary. */
 router_info routers_available[] = {
 #ifdef ROUTER_ACCEPT
   {
-  .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,
+  .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
@@ -282,12 +284,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_DNSLOOKUP
   {
-  .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,
+  .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
@@ -295,12 +299,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_IPLITERAL
   {
-  .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,
+  .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
@@ -308,12 +314,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_IPLOOKUP
   {
-  .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,
+  .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
@@ -321,12 +329,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_MANUALROUTE
   {
-  .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,
+  .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
@@ -334,12 +344,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_QUERYPROGRAM
   {
-  .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,
+  .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
@@ -347,12 +359,14 @@ router_info routers_available[] = {
 #endif
 #ifdef ROUTER_REDIRECT
   {
-  .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,
+  .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
@@ -466,8 +480,8 @@ gstring *
 route_show_supported(gstring * g)
 {
 g = string_cat(g, US"Routers:");
-for (router_info * rr = routers_available; rr->driver_name[0]; rr++)
-           g = string_fmt_append(g, " %s", rr->driver_name);
+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");
 }


@@ -555,8 +569,8 @@ lookup_list[pos] = info;


/* These need to be at file level for old versions of gcc (2.95.2 reported),
- * which give parse errors on an extern in function scope. Each entry needs
- * to also be invoked in init_lookup_list() below */
+which give parse errors on an extern in function scope. Each entry needs
+to also be invoked in init_lookup_list() below */

 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
 extern lookup_module_info cdb_lookup_module_info;
diff --git a/src/src/expand.c b/src/src/expand.c
index 4135574d6..2ed802fd4 100644
--- a/src/src/expand.c
+++ b/src/src/expand.c
@@ -1044,9 +1044,10 @@ Returns:        TRUE if condition is met, FALSE if not
 */


 BOOL
-expand_check_condition(uschar *condition, uschar *m1, uschar *m2)
+expand_check_condition(const uschar * condition,
+  const uschar * m1, const uschar * m2)
 {
-uschar * ss = expand_string(condition);
+const uschar * ss = expand_cstring(condition);
 if (!ss)
   {
   if (!f.expand_string_forcedfail && !f.search_find_defer)
@@ -8701,16 +8702,16 @@ Returns:     OK     value placed in rvalue


int
exp_bool(address_item * addr,
- uschar * mtype, uschar * mname, unsigned dbg_opt,
+ const uschar * mtype, const uschar * mname, unsigned dbg_opt,
uschar * oname, BOOL bvalue,
- uschar * svalue, BOOL * rvalue)
+ const uschar * svalue, BOOL * rvalue)
{
-uschar * expanded;
+const uschar * expanded;

DEBUG(D_expand) debug_printf("try option %s\n", oname);
if (!svalue) { *rvalue = bvalue; return OK; }

-if (!(expanded = expand_string(svalue)))
+if (!(expanded = expand_cstring(svalue)))
   {
   if (f.expand_string_forcedfail)
     {
diff --git a/src/src/functions.h b/src/src/functions.h
index 5d20bb2fc..884b6fd77 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -263,10 +263,10 @@ extern void    exim_nullstd(void);
 extern void    exim_setugid(uid_t, gid_t, BOOL, const uschar *);
 extern void    exim_underbar_exit(int) NORETURN;
 extern void    exim_wait_tick(struct timeval *, int);
-extern int     exp_bool(address_item *addr,
-  uschar *mtype, uschar *mname, unsigned dgb_opt, uschar *oname, BOOL bvalue,
-  uschar *svalue, BOOL *rvalue);
-extern BOOL    expand_check_condition(uschar *, uschar *, uschar *);
+extern int     exp_bool(address_item *,
+  const uschar *, const uschar *, unsigned, uschar *, BOOL bvalue,
+  const uschar *, BOOL *);
+extern BOOL    expand_check_condition(const uschar *, const uschar *, const uschar *);
 extern uschar *expand_file_big_buffer(const uschar *);
 extern uschar *expand_string(uschar *);    /* public, cannot make const */
 extern const uschar *expand_string_2(const uschar *, BOOL *);
diff --git a/src/src/globals.c b/src/src/globals.c
index 02349497f..6f43b97d8 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -1367,88 +1367,28 @@ uid_t   root_gid               = ROOT_GID;
 uid_t   root_uid               = ROOT_UID;


 router_instance  *routers  = NULL;
-router_instance  router_defaults = {
-    .next =            NULL,
-    .name =            NULL,
-    .info =            NULL,
-    .options_block =        NULL,
-    .driver_name =        NULL,


-    .address_data =        NULL,
-#ifdef EXPERIMENTAL_BRIGHTMAIL
-    .bmi_rule =            NULL,
-#endif
-    .cannot_route_message =    NULL,
-    .condition =        NULL,
-    .current_directory =    NULL,
-    .debug_string =        NULL,
-    .domains =            NULL,
-    .errors_to =        NULL,
-    .expand_gid =        NULL,
-    .expand_uid =        NULL,
-    .expand_more =        NULL,
-    .expand_unseen =        NULL,
-    .extra_headers =        NULL,
-    .fallback_hosts =        NULL,
-    .home_directory =        NULL,
-    .ignore_target_hosts =    NULL,
-    .local_parts =        NULL,
-    .pass_router_name =        NULL,
-    .prefix =            NULL,
-    .redirect_router_name =    NULL,
-    .remove_headers =        NULL,
-    .require_files =        NULL,
-    .router_home_directory =    NULL,
+/* All elements not mentioned will be 0/NULL/FALSE */
+router_instance  router_defaults = {
     .self =            US"freeze",
-    .senders =            NULL,
-    .suffix =            NULL,
-    .translate_ip_address =    NULL,
-    .transport_name =        NULL,


     .address_test =        TRUE,
-#ifdef EXPERIMENTAL_BRIGHTMAIL
-    .bmi_deliver_alternate =    FALSE,
-    .bmi_deliver_default =    FALSE,
-    .bmi_dont_deliver =        FALSE,
-#endif
     .expn =            TRUE,
-    .caseful_local_part =    FALSE,
-    .check_local_user =        FALSE,
-    .disable_logging =        FALSE,
-    .fail_verify_recipient =    FALSE,
-    .fail_verify_sender =    FALSE,
-    .gid_set =            FALSE,
-    .initgroups =        FALSE,
     .log_as_local =        TRUE_UNSET,
     .more =            TRUE,
-    .pass_on_timeout =        FALSE,
-    .prefix_optional =        FALSE,
     .repeat_use =        TRUE,
     .retry_use_local_part =    TRUE_UNSET,
-    .same_domain_copy_routing =    FALSE,
-    .self_rewrite =        FALSE,
-    .set =            NULL,
-    .suffix_optional =        FALSE,
-    .verify_only =        FALSE,
     .verify_recipient =        TRUE,
     .verify_sender =        TRUE,
-    .uid_set =            FALSE,
-    .unseen =            FALSE,
-    .dsn_lasthop =        FALSE,


     .self_code =        self_freeze,
     .uid =            (uid_t)(-1),
     .gid =            (gid_t)(-1),


-    .fallback_hostlist =    NULL,
-    .transport =        NULL,
-    .pass_router =        NULL,
-    .redirect_router =        NULL,
-
     .dnssec =                   { .request= US"*", .require=NULL },
 };


-uschar *router_name            = NULL;
+const uschar *router_name      = NULL;
 tree_node *router_var           = NULL;


 ip_address_item *running_interfaces = NULL;
diff --git a/src/src/globals.h b/src/src/globals.h
index 65eb4e4a5..698bbd12f 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -949,7 +949,7 @@ extern uid_t   root_uid;               /* The uid for root */
 extern router_info routers_available[];/* Vector of available routers */
 extern router_instance *routers;       /* Chain of instantiated routers */
 extern router_instance router_defaults;/* Default values */
-extern uschar *router_name;            /* Name of router last started */
+extern const uschar *router_name;      /* Name of router last started */
 extern tree_node *router_var;           /* Variables set by router */
 extern ip_address_item *running_interfaces; /* Host's running interfaces */
 extern uschar *running_status;         /* Flag string for testing */
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 940c5d4d3..80b66a910 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -615,85 +615,92 @@ for (optionlist * o = optionlist_config;           /* main-config options */
   if (listptr == o->v.value)
     return US o->name;


-for (router_instance * r = routers; r; r = r->next)
-  if (router_name && Ustrcmp(r->name, router_name) == 0)
-  {
-  const router_info * ri = r->info;
-
-  /* Check for a listptr match first */
-
-  for (optionlist * o = optionlist_routers;        /* generic options */
-      o < optionlist_routers + optionlist_routers_size; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && listptr == CS r + o->v.offset)
-      return US o->name;
-
-  for (optionlist * o = ri->options;            /* private options */
-      o < ri->options + *ri->options_count; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && listptr == CS (r->options_block) + o->v.offset)
-      return US o->name;
-
-  /* Check for a list addr match, unless null */
-
-  if (!list) continue;
-
-  for (optionlist * o = optionlist_routers;        /* generic options */
-      o < optionlist_routers + optionlist_routers_size; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && list == * USS(CS r + o->v.offset))
-      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
-    drname, name, r->name, o->name);
-      else { name = US o->name; drname = r->name; }
-
-  for (optionlist * o = ri->options;            /* private options */
-      o < ri->options + *ri->options_count; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && list == * USS(CS (r->options_block) + o->v.offset))
-      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
-    drname, name, r->name, o->name);
-      else { name = US o->name; drname = r->name; }
-  }
+if (router_name)
+  for (const driver_instance * rd = (driver_instance *)routers;
+    rd; rd = rd->next) if (Ustrcmp(rd->name, router_name) == 0)
+    {
+    const router_instance * r = (router_instance *)rd;
+    const router_info * ri = (router_info *)rd->info;
+
+    /* Check for a listptr match first */
+
+    for (optionlist * o = optionlist_routers;        /* generic options */
+    o < optionlist_routers + optionlist_routers_size; o++)
+      if (  (o->type & opt_mask) == opt_stringptr
+     && listptr == CS r + o->v.offset)
+    return US o->name;
+
+    for (optionlist * o = ri->drinfo.options;        /* private options */
+    o < ri->drinfo.options + *ri->drinfo.options_count; o++)
+      if (  (o->type & opt_mask) == opt_stringptr
+     && listptr == CS rd->options_block + o->v.offset)
+    return US o->name;
+
+    /* Check for a list addr match, unless null */
+
+    if (!list) continue;
+
+    for (optionlist * o = optionlist_routers;        /* generic options */
+    o < optionlist_routers + optionlist_routers_size; o++)
+      if (  (o->type & opt_mask) == opt_stringptr
+     && list == * USS(CS r + o->v.offset))
+    if (name)
+      return string_sprintf("DUP: %s %s vs. %s %s",
+                drname, name, rd->name, o->name);
+    else
+      { name = US o->name; drname = rd->name; }
+
+    for (optionlist * o = ri->drinfo.options;        /* private options */
+    o < ri->drinfo.options + *ri->drinfo.options_count; o++)
+      if (  (o->type & opt_mask) == opt_stringptr
+     && list == * USS(CS rd->options_block + o->v.offset))
+    if (name)
+      return string_sprintf("DUP: %s %s vs. %s %s",
+                drname, name, rd->name, o->name);
+    else
+      { name = US o->name; drname = rd->name; }
+    }


-for (transport_instance * t = transports; t; t = t->next)
-  if (transport_name && Ustrcmp(t->name, transport_name) == 0)
-  {
-  const transport_info * ti = t->info;
-
-  /* Check for a listptr match first */
-
-  for (optionlist * o = optionlist_transports;        /* generic options */
-      o < optionlist_transports + optionlist_transports_size; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && listptr == CS t + o->v.offset)
-      return US o->name;
-
-  for (optionlist * o = ti->options;            /* private options */
-      o < ti->options + *ti->options_count; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && listptr == CS t->options_block + o->v.offset)
-      return US o->name;
-
-  /* Check for a list addr match, unless null */
-
-  if (!list) continue;
-
-  for (optionlist * o = optionlist_transports;        /* generic options */
-      o < optionlist_transports + optionlist_transports_size; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && list == * USS(CS t + o->v.offset))
-      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
-    drname, name, t->name, o->name);
-      else { name = US o->name; drname = t->name; }
-
-  for (optionlist * o = ti->options;            /* private options */
-      o < ti->options + *ti->options_count; o++)
-    if (  (o->type & opt_mask) == opt_stringptr
-       && list == * USS(CS t->options_block + o->v.offset))
-      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
-    drname, name, t->name, o->name);
-      else { name = US o->name; drname = t->name; }
-  }
+if (transport_name)
+  for (transport_instance * t = transports; t; t = t->next)
+    if (Ustrcmp(t->name, transport_name) == 0)
+      {
+      const transport_info * ti = t->info;
+
+      /* Check for a listptr match first */
+
+      for (optionlist * o = optionlist_transports;        /* generic options */
+      o < optionlist_transports + optionlist_transports_size; o++)
+    if (  (o->type & opt_mask) == opt_stringptr
+       && listptr == CS t + o->v.offset)
+      return US o->name;
+
+      for (optionlist * o = ti->options;            /* private options */
+      o < ti->options + *ti->options_count; o++)
+    if (  (o->type & opt_mask) == opt_stringptr
+       && listptr == CS t->options_block + o->v.offset)
+      return US o->name;
+
+      /* Check for a list addr match, unless null */
+
+      if (!list) continue;
+
+      for (optionlist * o = optionlist_transports;        /* generic options */
+      o < optionlist_transports + optionlist_transports_size; o++)
+    if (  (o->type & opt_mask) == opt_stringptr
+       && list == * USS(CS t + o->v.offset))
+      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+        drname, name, t->name, o->name);
+      else { name = US o->name; drname = t->name; }
+
+      for (optionlist * o = ti->options;            /* private options */
+      o < ti->options + *ti->options_count; o++)
+    if (  (o->type & opt_mask) == opt_stringptr
+       && list == * USS(CS t->options_block + o->v.offset))
+      if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+        drname, name, t->name, o->name);
+      else { name = US o->name; drname = t->name; }
+      }


 return name ? name : US"";
 }
@@ -3008,6 +3015,8 @@ if (names_only)
 for (; d; d = d->next)
   {
   BOOL rc = FALSE;
+  driver_info * di = d->info;
+
   if (!name)
     printf("\n%s %s:\n", d->name, type);
   else if (Ustrcmp(d->name, name) != 0) continue;
@@ -3016,11 +3025,11 @@ for (; d; d = d->next)
     if (!(ol->type & opt_hidden))
       rc |= print_ol(ol, US ol->name, d, ol2, size, no_labels);


-  for (optionlist * ol = d->info->options;
-       ol < d->info->options + *(d->info->options_count); ol++)
+  for (optionlist * ol = di->options;
+       ol < di->options + *di->options_count; ol++)
     if (!(ol->type & opt_hidden))
-      rc |= print_ol(ol, US ol->name, d, d->info->options,
-            *d->info->options_count, no_labels);
+      rc |= print_ol(ol, US ol->name, d, di->options,
+            *di->options_count, no_labels);


   if (name) return rc;
   }
@@ -3727,10 +3736,12 @@ return NULL;   /* never obeyed */
 static void
 driver_init_fini(driver_instance * d, const uschar * class)
 {
+driver_info * di = d->info;
+
 if (!d->driver_name)
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
     "no driver defined for %s \"%s\"", class, d->name);
-(d->info->init)(d);
+(di->init)(d);
 }



@@ -3826,7 +3837,7 @@ while ((buffer = get_config_line()))
     d = store_get_perm(instance_size, FALSE);
     memcpy(d, instance_default, instance_size);
     *p = d;
-    p = &d->next;
+    p = (driver_instance **)&d->next;
     d->name = string_copy(name);
     d->srcfile = config_filename;
     d->srcline = config_lineno; 
@@ -3865,8 +3876,11 @@ while ((buffer = get_config_line()))
   block. */


   else if (d->info)
-    readconf_handle_option(buffer, d->info->options,
-      *(d->info->options_count), d, US"option \"%s\" unknown");
+    {
+    driver_info * di = d->info;
+    readconf_handle_option(buffer, di->options,
+      *di->options_count, d, US"option \"%s\" unknown");
+    }


/* The option is not generic and the driver name has not yet been given. */

@@ -3898,12 +3912,13 @@ Returns: TRUE if a dependency is found
*/

BOOL
-readconf_depends(driver_instance *d, uschar *s)
+readconf_depends(driver_instance * d, uschar * s)
{
-int count = *(d->info->options_count);
-uschar *ss;
+driver_info * di = d->info;
+int count = *di->options_count;
+uschar * ss;

-for (optionlist * ol = d->info->options; ol < d->info->options + count; ol++)
+for (optionlist * ol = di->options; ol < di->options + count; ol++)
   if ((ol->type & opt_mask) == opt_stringptr)
     {
     void * options_block = ol->type & opt_public ? (void *)d : d->options_block;
diff --git a/src/src/route.c b/src/src/route.c
index f42afd2ef..c7ea67609 100644
--- a/src/src/route.c
+++ b/src/src/route.c
@@ -64,7 +64,7 @@ optionlist optionlist_routers[] = {
   { "domains",            opt_stringptr|opt_public,
                  LOFF(domains) },
   { "driver",             opt_stringptr|opt_public,
-                 LOFF(driver_name) },
+                 LOFF(drinst.driver_name) },
   { "dsn_lasthop",        opt_bool|opt_public,
                  LOFF(dsn_lasthop) },
   { "errors_to",          opt_stringptr|opt_public,
@@ -159,11 +159,12 @@ uschar buf[64];


options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);

-for (router_info * ri = routers_available; ri->driver_name[0]; ri++)
+for (router_info * ri = routers_available; ri->drinfo.driver_name[0]; ri++)
   {
-  spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", ri->driver_name);
+  spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", ri->drinfo.driver_name);
   builtin_macro_create(buf);
-  options_from_list(ri->options, (unsigned)*ri->options_count, US"ROUTER", ri->driver_name);
+  options_from_list(ri->drinfo.options, (unsigned)*ri->drinfo.options_count,
+            US"ROUTER", ri->drinfo.driver_name);
   }
 }


@@ -191,9 +192,9 @@ set_router(router_instance *r, uschar *name, router_instance **ptr, BOOL after)
BOOL afterthis = FALSE;
router_instance *rr;

-for (rr = routers; rr; rr = rr->next)
+for (rr = routers; rr; rr = rr->drinst.next)
   {
-  if (Ustrcmp(name, rr->name) == 0)
+  if (Ustrcmp(name, rr->drinst.name) == 0)
     {
     *ptr = rr;
     break;
@@ -203,11 +204,11 @@ for (rr = routers; rr; rr = rr->next)


 if (!rr)
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-    "new_router \"%s\" not found for \"%s\" router", name, r->name);
+    "new_router \"%s\" not found for \"%s\" router", name, r->drinst.name);


 if (after && !afterthis)
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-    "new_router \"%s\" does not follow \"%s\" router", name, r->name);
+    "new_router \"%s\" does not follow \"%s\" router", name, r->drinst.name);
 }



@@ -235,9 +236,10 @@ readconf_driver_init(US"router",
   optionlist_routers,                 /* generic options */
   optionlist_routers_size);


-for (router_instance * r = routers; r; r = r->next)
+for (router_instance * r = routers; r; r = r->drinst.next)
{
- uschar *s = r->self;
+ uschar * s = r->self;
+ router_info * ri = r->drinst.info;

/* If log_as_local is unset, its overall default is FALSE. (The accept
router defaults it to TRUE.) */
@@ -246,14 +248,13 @@ for (router_instance * r = routers; r; r = r->next)

/* Check for transport or no transport on certain routers */

-  if (  (r->info->ri_flags & ri_yestransport)
-     && !r->transport_name && !r->verify_only)
+  if (ri->ri_flags & ri_yestransport && !r->transport_name && !r->verify_only)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "%s router:\n  "
-      "a transport is required for this router", r->name);
+      "a transport is required for this router", r->drinst.name);


-  if ((r->info->ri_flags & ri_notransport) && r->transport_name)
+  if (ri->ri_flags & ri_notransport && r->transport_name)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "%s router:\n  "
-      "a transport must not be defined for this router", r->name);
+      "a transport must not be defined for this router", r->drinst.name);


   /* The "self" option needs to be decoded into a code value and possibly a
   new domain string and a rewrite boolean. */
@@ -278,7 +279,7 @@ for (router_instance * r = routers; r; r = r->next)
     }


   else log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
-      "%s is not valid for the self option", r->name, s);
+      "%s is not valid for the self option", r->drinst.name, s);


/* If any router has check_local_user set, default retry_use_local_part
TRUE; otherwise its default is FALSE. */
@@ -325,8 +326,11 @@ is finished, via this function. */
void
route_tidyup(void)
{
-for (router_instance * r = routers; r; r = r->next)
- if (r->info->tidyup) (r->info->tidyup)(r);
+for (router_instance * r = routers; r; r = r->drinst.next)
+ {
+ router_info * ri = r->drinst.info;
+ if (ri->tidyup) (ri->tidyup)(r);
+ }
}


@@ -463,9 +467,9 @@ Returns:         OK     item is in list
 */


static int
-route_check_dls(uschar *rname, uschar *type, const uschar *list,
- tree_node **anchorptr, unsigned int *cache_bits, int listtype,
- const uschar *domloc, const uschar **ldata, BOOL caseless, uschar **perror)
+route_check_dls(const uschar * rname, const uschar * type, const uschar * list,
+ tree_node ** anchorptr, unsigned int * cache_bits, int listtype,
+ const uschar * domloc, const uschar ** ldata, BOOL caseless, uschar ** perror)
{
if (!list) return OK; /* Empty list always succeeds */

@@ -863,6 +867,7 @@ check_router_conditions(router_instance * r, address_item * addr, int verify,
int rc;
uschar * check_local_part;
unsigned int * localpart_cache;
+const uschar * rname = r->drinst.name;

/* Reset variables to hold a home directory and data from lookup of a domain or
local part, and ensure search_find_defer is unset, in case there aren't any
@@ -880,7 +885,7 @@ f.search_find_defer = FALSE;

if ((verify == v_none || verify == v_expn) && r->verify_only)
{
- DEBUG(D_route) debug_printf("%s router skipped: verify_only set\n", r->name);
+ DEBUG(D_route) debug_printf("%s router skipped: verify_only set\n", rname);
return SKIP;
}

@@ -889,7 +894,7 @@ if ((verify == v_none || verify == v_expn) && r->verify_only)
 if (f.address_test_mode && !r->address_test)
   {
   DEBUG(D_route) debug_printf("%s router skipped: address_test is unset\n",
-    r->name);
+    rname);
   return SKIP;
   }


@@ -900,7 +905,7 @@ if ((verify == v_sender && !r->verify_sender) ||
     (verify == v_recipient && !r->verify_recipient))
   {
   DEBUG(D_route) debug_printf("%s router skipped: verify %d %d %d\n",
-    r->name, verify, r->verify_sender, r->verify_recipient);
+    rname, verify, r->verify_sender, r->verify_recipient);
   return SKIP;
   }


@@ -908,13 +913,13 @@ if ((verify == v_sender && !r->verify_sender) ||

if (verify == v_expn && !r->expn)
{
- DEBUG(D_route) debug_printf("%s router skipped: no_expn set\n", r->name);
+ DEBUG(D_route) debug_printf("%s router skipped: no_expn set\n", rname);
return SKIP;
}

/* Skip this router if there's a domain mismatch. */

-if ((rc = route_check_dls(r->name, US"domains", r->domains, &domainlist_anchor,
+if ((rc = route_check_dls(rname, US"domains", r->domains, &domainlist_anchor,
      addr->domain_cache, TRUE, addr->domain, CUSS &deliver_domain_data,
      MCL_DOMAIN, perror)) != OK)
   return rc;
@@ -938,7 +943,7 @@ else
     check_local_part[Ustrlen(check_local_part) - Ustrlen(addr->suffix)] = 0;
   }


-if ((rc = route_check_dls(r->name, US"local_parts", r->local_parts,
+if ((rc = route_check_dls(rname, US"local_parts", r->local_parts,
        &localpartlist_anchor, localpart_cache, MCL_LOCALPART,
        check_local_part, CUSS &deliver_localpart_data,
        !r->caseful_local_part, perror)) != OK)
@@ -956,7 +961,7 @@ if (r->check_local_user)
   if (!route_finduser(addr->local_part, pw, NULL))
     {
     DEBUG(D_route) debug_printf("%s router skipped: %s is not a local user\n",
-      r->name, addr->local_part);
+      rname, addr->local_part);
     return SKIP;
     }
   addr->prop.localpart_data =
@@ -994,7 +999,7 @@ if (r->router_home_directory)
 local user check so that $home is set - enabling the possibility of letting
 individual recipients specify lists of acceptable/unacceptable senders. */


-if ((rc = route_check_dls(r->name, US"senders", r->senders, NULL,
+if ((rc = route_check_dls(rname, US"senders", r->senders, NULL,
      sender_address_cache, MCL_ADDRESS, NULL, NULL, FALSE, perror)) != OK)
   return rc;


@@ -1008,7 +1013,7 @@ debug_print_string(r->debug_string);

 if ((rc = check_files(r->require_files, perror)) != OK)
   {
-  DEBUG(D_route) debug_printf("%s router %s: file check\n", r->name,
+  DEBUG(D_route) debug_printf("%s router %s: file check\n", rname,
     (rc == SKIP)? "skipped" : "deferred");
   return rc;
   }
@@ -1019,7 +1024,7 @@ if (r->condition)
   {
   DEBUG(D_route|D_expand)
     debug_printf("checking \"condition\" \"%.80s\"...\n", r->condition);
-  if (!expand_check_condition(r->condition, r->name, US"router"))
+  if (!expand_check_condition(r->condition, rname, US"router"))
     {
     if (f.search_find_defer)
       {
@@ -1028,7 +1033,7 @@ if (r->condition)
       return DEFER;
       }
     DEBUG(D_route)
-      debug_printf("%s router skipped: condition failure\n", r->name);
+      debug_printf("%s router skipped: condition failure\n", rname);
     return SKIP;
     }
   }
@@ -1041,7 +1046,7 @@ if (r->bmi_rule)
   if (bmi_check_rule(bmi_base64_verdict, r->bmi_rule) == 0)
     {    /* none of the rules fired */
     DEBUG(D_route)
-      debug_printf("%s router skipped: none of bmi_rule rules fired\n", r->name);
+      debug_printf("%s router skipped: none of bmi_rule rules fired\n", rname);
     return SKIP;
     }
   }
@@ -1050,7 +1055,7 @@ if (r->bmi_rule)
 if (r->bmi_dont_deliver && bmi_deliver == 1)
   {
   DEBUG(D_route)
-    debug_printf("%s router skipped: bmi_dont_deliver is FALSE\n", r->name);
+    debug_printf("%s router skipped: bmi_dont_deliver is FALSE\n", rname);
   return SKIP;
   }


@@ -1060,7 +1065,7 @@ if (  r->bmi_deliver_alternate
    )
   {
   DEBUG(D_route)
-    debug_printf("%s router skipped: bmi_deliver_alternate is FALSE\n", r->name);
+    debug_printf("%s router skipped: bmi_deliver_alternate is FALSE\n", rname);
   return SKIP;
   }


@@ -1070,7 +1075,7 @@ if (  r->bmi_deliver_default
    )
   {
   DEBUG(D_route)
-    debug_printf("%s router skipped: bmi_deliver_default is FALSE\n", r->name);
+    debug_printf("%s router skipped: bmi_deliver_default is FALSE\n", rname);
   return SKIP;
   }
 #endif
@@ -1355,8 +1360,9 @@ Returns:        nothing
 */


static void
-route_unseen(uschar *name, address_item *addr, address_item **paddr_local,
- address_item **paddr_remote, address_item **addr_new)
+route_unseen(const uschar * name, address_item * addr,
+ address_item **paddr_local, address_item ** paddr_remote,
+ address_item ** addr_new)
{
address_item *parent = deliver_make_addr(addr->address, TRUE);
address_item *new = deliver_make_addr(addr->address, TRUE);
@@ -1392,17 +1398,16 @@ new->dsn_orcpt = addr->dsn_orcpt;


/* As it has turned out, we haven't set headers_add or headers_remove for the
- * clone. Thinking about it, it isn't entirely clear whether they should be
- * copied from the original parent, like errors_address, or taken from the
- * unseen router, like address_data and the flags. Until somebody brings this
- * up, I propose to leave the code as it is.
- */
+clone. Thinking about it, it isn't entirely clear whether they should be
+copied from the original parent, like errors_address, or taken from the
+unseen router, like address_data and the flags. Until somebody brings this
+up, I propose to leave the code as it is. */


/* Set the cloned address to start at the next router, and put it onto the
chain of new addresses. */

-new->start_router = addr->router->next;
+new->start_router = addr->router->drinst.next;
new->next = *addr_new;
*addr_new = new;

@@ -1439,6 +1444,7 @@ set_router_vars(address_item * addr, const router_instance * r)
const uschar * varlist = r->set;
tree_node ** root = (tree_node **) &addr->prop.variables;
int sep = ';';
+const uschar * drname = r->drinst.name;

 GET_OPTION("set");
 if (!varlist) return OK;
@@ -1458,7 +1464,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); )
   if (!name || name[0] != 'r' || name[1] != '_' || !name[2])
     {
     log_write(0, LOG_MAIN|LOG_PANIC,
-    "bad router variable name '%s' in router '%s'\n", name, r->name);
+    "bad router variable name '%s' in router '%s'\n", name, drname);
     return FAIL;
     }
   name += 2;
@@ -1476,7 +1482,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); )
       /* Expand "more" if necessary; DEFER => an expansion failed */


       GET_OPTION("more");
-      yield = exp_bool(addr, US"router", r->name, D_route,
+      yield = exp_bool(addr, US"router", drname, D_route,
               US"more", r->more, r->expand_more, &more);
       if (yield != OK) return yield;


@@ -1493,7 +1499,7 @@ for (uschar * ele; (ele = string_nextinlist(&varlist, &sep, NULL, 0)); )
     else
       {
       addr->message = string_sprintf("expansion of \"%s\" failed "
-    "in %s router: %s", ele, r->name, expand_string_message);
+    "in %s router: %s", ele, drname, expand_string_message);
       /* Caller will replace that for logging, if a DB lookup, to avoid exposing
       passwords */
       DEBUG(D_route) debug_printf("%s\n", addr->message);
@@ -1554,6 +1560,7 @@ int yield = OK;
 BOOL unseen;
 router_instance * r, * nextr;
 const uschar * old_domain = addr->domain;
+const uschar * rname_l;


HDEBUG(D_route)
{
@@ -1570,12 +1577,11 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
uschar * error;
struct passwd * pw = NULL;
struct passwd pwcopy;
- BOOL loop_detected = FALSE;
- BOOL more;
- int loopcount = 0;
- int rc;
+ BOOL loop_detected = FALSE, more;
+ int loopcount = 0, rc;

- DEBUG(D_route) debug_printf("--------> %s router <--------\n", r->name);
+ rname_l = r->drinst.name;
+ DEBUG(D_route) debug_printf("--------> %s router <--------\n", rname_l);

/* Reset any search error message from the previous router. */

@@ -1589,7 +1595,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
next router. */

addr->router = r;
- nextr = r->next;
+ nextr = r->drinst.next;

   /* Loop protection: If this address has an ancestor with the same address,
   and that ancestor was routed by this router, we skip this router. This
@@ -1625,7 +1631,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
       if (break_loop)
         {
         DEBUG(D_route) debug_printf("%s router skipped: previously routed %s\n",
-          r->name, parent->address);
+          rname_l, parent->address);
         loop_detected = TRUE;
         break;
         }
@@ -1680,8 +1686,8 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
       }
     else if (!r->prefix_optional)
       {
-      DEBUG(D_route) debug_printf("%s router skipped: prefix mismatch\n",
-        r->name);
+      DEBUG(D_route)
+    debug_printf("%s router skipped: prefix mismatch\n", rname_l);
       continue;
       }
     }
@@ -1704,8 +1710,8 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
       }
     else if (!r->suffix_optional)
       {
-      DEBUG(D_route) debug_printf("%s router skipped: suffix mismatch\n",
-        r->name);
+      DEBUG(D_route)
+    debug_printf("%s router skipped: suffix mismatch\n", rname_l);
       continue;
       }
     }
@@ -1713,9 +1719,9 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
   /* Set the expansion variables now that we have the affixes and the case of
   the local part sorted. */


- router_name = r->name;
- driver_srcfile = r->srcfile;
- driver_srcline = r->srcline;
+ router_name = rname_l;
+ driver_srcfile = r->drinst.srcfile;
+ driver_srcline = r->drinst.srcline;
deliver_set_expansions(addr);

   /* For convenience, the pre-router checks are in a separate function, which
@@ -1767,7 +1773,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
         /* Expand "more" if necessary; DEFER => an expansion failed */


     GET_OPTION("more");
-        yield = exp_bool(addr, US"router", r->name, D_route,
+        yield = exp_bool(addr, US"router", rname_l, D_route,
             US"more", r->more, r->expand_more, &more);
         if (yield != OK) goto ROUTE_EXIT;


@@ -1785,7 +1791,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
       else
         {
         addr->message = string_sprintf("expansion of \"%s\" failed "
-          "in %s router: %s", r->address_data, r->name, expand_string_message);
+          "in %s router: %s", r->address_data, rname_l, expand_string_message);
         yield = DEFER;
         goto ROUTE_EXIT;
         }
@@ -1822,16 +1828,19 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)


/* Run the router, and handle the consequences. */

- HDEBUG(D_route) debug_printf("calling %s router\n", r->name);
+ HDEBUG(D_route) debug_printf("calling %s router\n", rname_l);

-  yield = (r->info->code)(r, addr, pw, verify, paddr_local, paddr_remote,
-    addr_new, addr_succeed);
+    {
+    router_info * ri = r->drinst.info;
+    yield = (ri->code)(r, addr, pw, verify, paddr_local, paddr_remote,
+      addr_new, addr_succeed);
+    }


driver_srcfile = router_name = NULL; driver_srcline = 0;

   if (yield == FAIL)
     {
-    HDEBUG(D_route) debug_printf("%s router forced address failure\n", r->name);
+    HDEBUG(D_route) debug_printf("%s router forced address failure\n", rname_l);
     goto ROUTE_EXIT;
     }


@@ -1843,7 +1852,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
     )
      && (yield == OK || yield == PASS))
     {
-    addr->message = string_sprintf("%s router forced verify failure", r->name);
+    addr->message = string_sprintf("%s router forced verify failure", rname_l);
     if (*paddr_remote == addr) *paddr_remote = addr->next;
     if (*paddr_local == addr) *paddr_local = addr->next;
     yield = FAIL;
@@ -1857,7 +1866,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)


   HDEBUG(D_route)
     {
-    debug_printf("%s router %s for %s\n", r->name,
+    debug_printf("%s router %s for %s\n", rname_l,
       yield == PASS ? "passed" : "declined", addr->address);
     if (Ustrcmp(old_domain, addr->domain) != 0)
       debug_printf("domain %s rewritten\n", old_domain);
@@ -1876,7 +1885,7 @@ for (r = addr->start_router ? addr->start_router : routers; r; r = nextr)
     /* Expand "more" if necessary */


     GET_OPTION("more");
-    yield = exp_bool(addr, US"router", r->name, D_route,
+    yield = exp_bool(addr, US"router", rname_l, D_route,
                    US"more", r->more, r->expand_more, &more);
     if (yield != OK) goto ROUTE_EXIT;


@@ -1913,7 +1922,8 @@ if (!r)
     else
       if (!f.expand_string_forcedfail)
         log_write(0, LOG_MAIN|LOG_PANIC, "failed to expand "
-          "cannot_route_message in %s router: %s", addr->router->name,
+          "cannot_route_message in %s router: %s",
+          addr->router->drinst.name,
           expand_string_message);
     }
       }
@@ -1927,7 +1937,7 @@ if (!r)
 if (yield == DEFER)
   {
   HDEBUG(D_route) debug_printf("%s router: defer for %s\n  message: %s\n",
-      r->name, addr->address, addr->message ? addr->message : US"<none>");
+      rname_l, addr->address, addr->message ? addr->message : US"<none>");
   goto ROUTE_EXIT;
   }


@@ -1937,7 +1947,7 @@ if (yield == DISCARD) goto ROUTE_EXIT;

 if (yield != OK && yield != REROUTED)
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router returned unknown value %d",
-    r->name, yield);
+    rname_l, yield);


/* If the yield was REROUTED, the router put a child address on the new chain
as a result of a domain change of some sort (widening, typically). */
@@ -2016,14 +2026,14 @@ if (r->translate_ip_address)
/* See if this is an unseen routing; first expand the option if necessary.
DEFER can be given if the expansion fails */

-yield = exp_bool(addr, US"router", r->name, D_route,
+yield = exp_bool(addr, US"router", rname_l, D_route,
                US"unseen", r->unseen, r->expand_unseen, &unseen);
 if (yield != OK) goto ROUTE_EXIT;


/* Debugging output recording a successful routing */

-HDEBUG(D_route) debug_printf("routed by %s router%s\n", r->name,
-    unseen? " (unseen)" : "");
+HDEBUG(D_route) debug_printf("routed by %s router%s\n", rname_l,
+    unseen ? " (unseen)" : "");


DEBUG(D_route)
{
@@ -2050,8 +2060,8 @@ DEBUG(D_route)
the "unseen" option (ignore if there are no further routers). */

addr->message = NULL;
-if (unseen && r->next)
- route_unseen(r->name, addr, paddr_local, paddr_remote, addr_new);
+if (unseen && r->drinst.next)
+ route_unseen(rname_l, addr, paddr_local, paddr_remote, addr_new);

/* Unset the address expansions, and return the final result. */

diff --git a/src/src/routers/accept.c b/src/src/routers/accept.c
index c747a8ba3..6cbde6dec 100644
--- a/src/src/routers/accept.c
+++ b/src/src/routers/accept.c
@@ -39,7 +39,7 @@ accept_router_options_block accept_router_option_defaults = {
#ifdef MACRO_PREDEF

/* Dummy entries */
-void accept_router_init(router_instance *rblock) {}
+void accept_router_init(driver_instance *rblock) {}
int accept_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -56,8 +56,10 @@ int accept_router_entry(router_instance *rblock, address_item *addr,
/* Called for each instance, after its options have been read, to enable
consistency checks to be done, or anything else that needs to be set up. */

-void accept_router_init(router_instance *rblock)
+void
+accept_router_init(driver_instance * r)
{
+router_instance * rblock = (router_instance *)r;
/*
accept_router_options_block *ob =
(accept_router_options_block *)(rblock->options_block);
@@ -111,7 +113,7 @@ uschar * remove_headers;
header_line * extra_headers;

DEBUG(D_route) debug_printf("%s router called for %s\n domain = %s\n",
- rblock->name, addr->address, addr->domain);
+ rblock->drinst.name, addr->address, addr->domain);

/* Set up the errors address, if any. */

@@ -128,7 +130,7 @@ header munging. Initialization ensures that there is a transport except when
verifying. */

if (!rf_get_transport(rblock->transport_name, &(rblock->transport),
- addr, rblock->name, NULL)) return DEFER;
+ addr, rblock->drinst.name, NULL)) return DEFER;

addr->transport = rblock->transport;
addr->prop.errors_address = errors_to;
diff --git a/src/src/routers/accept.h b/src/src/routers/accept.h
index ca768b26e..655056af1 100644
--- a/src/src/routers/accept.h
+++ b/src/src/routers/accept.h
@@ -27,6 +27,6 @@ extern int accept_router_entry(router_instance *, address_item *,
struct passwd *, int, address_item **, address_item **,
address_item **, address_item **);

-extern void accept_router_init(router_instance *);
+extern void accept_router_init(driver_instance *);

/* End of routers/accept.h */
diff --git a/src/src/routers/dnslookup.c b/src/src/routers/dnslookup.c
index ef8243818..8a6f72d5d 100644
--- a/src/src/routers/dnslookup.c
+++ b/src/src/routers/dnslookup.c
@@ -45,7 +45,7 @@ int dnslookup_router_options_count =

/* Dummy entries */
dnslookup_router_options_block dnslookup_router_option_defaults = {0};
-void dnslookup_router_init(router_instance *rblock) {}
+void dnslookup_router_init(driver_instance *rblock) {}
int dnslookup_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -83,7 +83,7 @@ dnslookup_router_options_block dnslookup_router_option_defaults = {
consistency checks to be done, or anything else that needs to be set up. */

void
-dnslookup_router_init(router_instance *rblock)
+dnslookup_router_init(driver_instance *rblock)
{
/*
dnslookup_router_options_block *ob =
@@ -154,7 +154,7 @@ int rc;
int widen_sep = 0;
int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
dnslookup_router_options_block * ob =
- (dnslookup_router_options_block *)(rblock->options_block);
+ (dnslookup_router_options_block *)(rblock->drinst.options_block);
uschar * srv_service = NULL, * widen = NULL;
const uschar * pre_widen = addr->domain, * post_widen = NULL;
const uschar * fully_qualified_name, * listptr;
@@ -162,7 +162,7 @@ uschar widen_buffer[256];

 DEBUG(D_route)
   debug_printf("%s router called for %s\n  domain = %s\n",
-    rblock->name, addr->address, addr->domain);
+    rblock->drinst.name, addr->address, addr->domain);


/* If an SRV check is required, expand the service name */

@@ -172,7 +172,7 @@ if (ob->check_srv)
      && !f.expand_string_forcedfail)
     {
     addr->message = string_sprintf("%s router: failed to expand \"%s\": %s",
-      rblock->name, ob->check_srv, expand_string_message);
+      rblock->drinst.name, ob->check_srv, expand_string_message);
     return DEFER;
     }
   else
@@ -237,27 +237,27 @@ for (;;)
     /* not expanded so should never be tainted */
     widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
       sizeof(widen_buffer));
-    DEBUG(D_route) debug_printf("%s router widened %s to %s\n", rblock->name,
-      addr->domain, h.name);
+    DEBUG(D_route) debug_printf("%s router widened %s to %s\n",
+      rblock->drinst.name, addr->domain, h.name);
     }
   else if (post_widen)
     {
     h.name = post_widen;
     post_widen = NULL;
     DEBUG(D_route) debug_printf("%s router trying %s after widening failed\n",
-      rblock->name, h.name);
+      rblock->drinst.name, h.name);
     }
   else return DECLINE;


/* Check if we must request only. or prefer, ipv4 */

   if (  ob->ipv4_only
-     && expand_check_condition(ob->ipv4_only, rblock->name, US"router"))
+     && expand_check_condition(ob->ipv4_only, rblock->drinst.name, US"router"))
     flags = flags & ~HOST_FIND_BY_AAAA | HOST_FIND_IPV4_ONLY;
   else if (f.search_find_defer)
     return DEFER;
   if (  ob->ipv4_prefer
-     && expand_check_condition(ob->ipv4_prefer, rblock->name, US"router"))
+     && expand_check_condition(ob->ipv4_prefer, rblock->drinst.name, US"router"))
     flags |= HOST_FIND_IPV4_FIRST;
   else if (f.search_find_defer)
     return DEFER;
@@ -314,7 +314,7 @@ for (;;)


       case OK:
       DEBUG(D_route) debug_printf("%s router rejected %s: no MX record(s)\n",
-        rblock->name, fully_qualified_name);
+        rblock->drinst.name, fully_qualified_name);
       continue;
       }


@@ -331,7 +331,7 @@ for (;;)
     if (rblock->pass_on_timeout)
       {
       DEBUG(D_route) debug_printf("%s router timed out, and pass_on_timeout is set\n",
-        rblock->name);
+        rblock->drinst.name);
       return PASS;
       }
     addr->message = US"host lookup did not complete";
@@ -351,7 +351,7 @@ for (;;)


       case OK:
     DEBUG(D_route) debug_printf("%s router: matched fail_defer_domains\n",
-      rblock->name);
+      rblock->drinst.name);
     addr->message = US"missing MX, or all MXs point to missing A records,"
       " and defer requested";
     return DEFER;
@@ -467,13 +467,12 @@ addr->host_list[0] = h;
 /* Fill in the transport and queue the address for delivery. */


 if (!rf_get_transport(rblock->transport_name, &(rblock->transport),
-      addr, rblock->name, NULL))
+      addr, rblock->drinst.name, NULL))
   return DEFER;


addr->transport = rblock->transport;

-return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
- OK : DEFER;
+return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ? OK : DEFER;
}

 #endif    /*!MACRO_PREDEF*/
diff --git a/src/src/routers/dnslookup.h b/src/src/routers/dnslookup.h
index ce1daf3c0..41c671132 100644
--- a/src/src/routers/dnslookup.h
+++ b/src/src/routers/dnslookup.h
@@ -38,6 +38,6 @@ extern int dnslookup_router_entry(router_instance *, address_item *,
   struct passwd *, int, address_item **, address_item **,
   address_item **, address_item **);


-extern void dnslookup_router_init(router_instance *);
+extern void dnslookup_router_init(driver_instance *);

/* End of routers/dnslookup.h */
diff --git a/src/src/routers/ipliteral.c b/src/src/routers/ipliteral.c
index 27c7fe6b3..790ef15f0 100644
--- a/src/src/routers/ipliteral.c
+++ b/src/src/routers/ipliteral.c
@@ -37,7 +37,7 @@ ipliteral_router_options_block ipliteral_router_option_defaults = { 0 };
#ifdef MACRO_PREDEF

/* Dummy entries */
-void ipliteral_router_init(router_instance *rblock) {}
+void ipliteral_router_init(driver_instance *rblock) {}
int ipliteral_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -54,7 +54,7 @@ int ipliteral_router_entry(router_instance *rblock, address_item *addr,
consistency checks to be done, or anything else that needs to be set up. */

void
-ipliteral_router_init(router_instance *rblock)
+ipliteral_router_init(driver_instance *rblock)
{
/*
ipliteral_router_options_block *ob =
@@ -119,7 +119,7 @@ int len = Ustrlen(domain);
int rc, ipv;

DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
- rblock->name, addr->address, addr->domain);
+ rblock->drinst.name, addr->address, addr->domain);

/* Check that the domain is an IP address enclosed in square brackets. Remember
to allow for the "official" form of IPv6 addresses. If not, the router
@@ -191,8 +191,8 @@ just verifying, there need not be a transport, in which case it doesn't matter
which queue we put the address on. This is all now handled by the route_queue()
function. */

-if (!rf_get_transport(rblock->transport_name, &(rblock->transport),
-      addr, rblock->name, NULL))
+if (!rf_get_transport(rblock->transport_name, &rblock->transport,
+      addr, rblock->drinst.name, NULL))
   return DEFER;


addr->transport = rblock->transport;
diff --git a/src/src/routers/ipliteral.h b/src/src/routers/ipliteral.h
index 7db24cfd1..897fd298a 100644
--- a/src/src/routers/ipliteral.h
+++ b/src/src/routers/ipliteral.h
@@ -30,6 +30,6 @@ extern int ipliteral_router_entry(router_instance *, address_item *,
struct passwd *, int, address_item **, address_item **,
address_item **, address_item **);

-extern void ipliteral_router_init(router_instance *);
+extern void ipliteral_router_init(driver_instance *);

/* End of routers/ipliteral.h */
diff --git a/src/src/routers/manualroute.c b/src/src/routers/manualroute.c
index d07ea3490..e2062bc8e 100644
--- a/src/src/routers/manualroute.c
+++ b/src/src/routers/manualroute.c
@@ -43,7 +43,7 @@ int manualroute_router_options_count =

/* Dummy entries */
manualroute_router_options_block manualroute_router_option_defaults = {0};
-void manualroute_router_init(router_instance *rblock) {}
+void manualroute_router_init(driver_instance *rblock) {}
int manualroute_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -91,7 +91,7 @@ static int hff_count= sizeof(hff_codes)/sizeof(int);
consistency checks to be done, or anything else that needs to be set up. */

void
-manualroute_router_init(router_instance *rblock)
+manualroute_router_init(driver_instance *rblock)
{
manualroute_router_options_block *ob =
(manualroute_router_options_block *)(rblock->options_block);
@@ -245,14 +245,14 @@ const uschar *hostlist = NULL;
const uschar *domain;
uschar *newhostlist;
const uschar *listptr;
-manualroute_router_options_block *ob =
- (manualroute_router_options_block *)(rblock->options_block);
+manualroute_router_options_block * ob =
+ (manualroute_router_options_block *)(rblock->drinst.options_block);
transport_instance *transport = NULL;
BOOL individual_transport_set = FALSE;
BOOL randomize = ob->hosts_randomize;

DEBUG(D_route) debug_printf("%s router called for %s\n domain = %s\n",
- rblock->name, addr->address, addr->domain);
+ rblock->drinst.name, addr->address, addr->domain);

 /* The initialization check ensures that either route_list or route_data is
 set. */
@@ -318,7 +318,7 @@ if (!newhostlist)
   {
   if (f.expand_string_forcedfail) return DECLINE;
   addr->message = string_sprintf("%s router: failed to expand \"%s\": %s",
-    rblock->name, hostlist, expand_string_message);
+    rblock->drinst.name, hostlist, expand_string_message);
   return DEFER;
   }
 else hostlist = newhostlist;
@@ -360,7 +360,7 @@ while (*options)
     if (!t)
       {
       s = string_sprintf("unknown routing option or transport name \"%s\"", s);
-      log_write(0, LOG_MAIN, "Error in %s router: %s", rblock->name, s);
+      log_write(0, LOG_MAIN, "Error in %s router: %s", rblock->drinst.name, s);
       addr->message = string_sprintf("error in router: %s", s);
       return DEFER;
       }
@@ -390,8 +390,8 @@ set. */


 if (!individual_transport_set)
   {
-  if (!rf_get_transport(rblock->transport_name, &(rblock->transport), addr,
-      rblock->name, NULL))
+  if (!rf_get_transport(rblock->transport_name, &rblock->transport, addr,
+      rblock->drinst.name, NULL))
     return DEFER;
   transport = rblock->transport;
   }
@@ -420,8 +420,7 @@ if (transport && transport->info->local)
   rf_queue_add() function. */


   addr->transport = transport;
-  return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
-    OK : DEFER;
+  return rf_queue_add(addr, addr_local, addr_remote, rblock, pw) ?  OK : DEFER;
   }


 /* There is either no transport (verify_only) or a remote transport. A host
@@ -432,7 +431,7 @@ if (!hostlist[0])
   {
   if (verify != v_none) goto ROUTED;
   addr->message = string_sprintf("error in %s router: no host(s) specified "
-    "for domain %s", rblock->name, addr->domain);
+    "for domain %s", rblock->drinst.name, addr->domain);
   log_write(0, LOG_MAIN, "%s", addr->message);
   return DEFER;
   }
@@ -460,7 +459,8 @@ if (!addr->host_list)
     if (ob->hai_code == hff_codes[i]) break;


   addr->message = string_sprintf("lookup failed for all hosts in %s router: "
-    "host_find_failed=ignore host_all_ignored=%s", rblock->name, hff_names[i]);
+    "host_find_failed=ignore host_all_ignored=%s",
+    rblock->drinst.name, hff_names[i]);


   if (ob->hai_code == hff_defer) return DEFER;
   if (ob->hai_code == hff_fail) return FAIL;
@@ -476,7 +476,7 @@ dealt with above. However, we don't need one if verifying only. */
 if (!transport && verify == v_none)
     {
     log_write(0, LOG_MAIN, "Error in %s router: no transport defined",
-      rblock->name);
+      rblock->drinst.name);
     addr->message = US"error in router: transport missing";
     return DEFER;
     }
diff --git a/src/src/routers/manualroute.h b/src/src/routers/manualroute.h
index 1201c8362..dc2745769 100644
--- a/src/src/routers/manualroute.h
+++ b/src/src/routers/manualroute.h
@@ -35,6 +35,6 @@ extern int manualroute_router_entry(router_instance *, address_item *,
   struct passwd *, int, address_item **, address_item **,
   address_item **, address_item **);


-extern void manualroute_router_init(router_instance *);
+extern void manualroute_router_init(driver_instance *);

/* End of routers/manualroute.h */
diff --git a/src/src/routers/queryprogram.c b/src/src/routers/queryprogram.c
index 235d0e769..83ffe239a 100644
--- a/src/src/routers/queryprogram.c
+++ b/src/src/routers/queryprogram.c
@@ -49,7 +49,7 @@ int queryprogram_router_options_count =

/* Dummy entries */
queryprogram_router_options_block queryprogram_router_option_defaults = {0};
-void queryprogram_router_init(router_instance *rblock) {}
+void queryprogram_router_init(driver_instance *rblock) {}
int queryprogram_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -82,7 +82,7 @@ queryprogram_router_options_block queryprogram_router_option_defaults = {
consistency checks to be done, or anything else that needs to be set up. */

void
-queryprogram_router_init(router_instance *rblock)
+queryprogram_router_init(driver_instance * rblock)
{
queryprogram_router_options_block *ob =
(queryprogram_router_options_block *)(rblock->options_block);
@@ -142,11 +142,11 @@ while (generated != NULL)

   if (addr->child_count == USHRT_MAX)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
-      "child addresses for <%s>", rblock->name, USHRT_MAX, addr->address);
+      "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address);
   addr->child_count++;


   DEBUG(D_route)
-    debug_printf("%s router generated %s\n", rblock->name, next->address);
+    debug_printf("%s router generated %s\n", rblock->drinst.name, next->address);
   }
 }


@@ -215,8 +215,8 @@ uschar buffer[1024];
const uschar **argvptr;
uschar *rword, *rdata, *s;
address_item_propagated addr_prop;
-queryprogram_router_options_block *ob =
- (queryprogram_router_options_block *)(rblock->options_block);
+queryprogram_router_options_block * ob =
+ (queryprogram_router_options_block *)(rblock->drinst.options_block);
uschar *current_directory = ob->current_directory;
ugid_block ugid;
uid_t curr_uid = getuid();
@@ -227,7 +227,7 @@ uid_t *puid = &uid;
gid_t *pgid = &gid;

DEBUG(D_route) debug_printf("%s router called for %s: domain = %s\n",
- rblock->name, addr->address, addr->domain);
+ rblock->drinst.name, addr->address, addr->domain);

ugid.uid_set = ugid.gid_set = FALSE;

@@ -249,8 +249,8 @@ if (rc != OK) return rc;
(initialization ensures that one or the other is set). */

 if (  !ob->cmd_uid_set
-   && !route_find_expanded_user(ob->expand_cmd_uid, rblock->name, US"router",
-    &upw, &uid, &(addr->message)))
+   && !route_find_expanded_user(ob->expand_cmd_uid, rblock->drinst.name,
+    US"router", &upw, &uid, &(addr->message)))
     return DEFER;


 /* Get the fixed or expanded gid, or take the gid from the passwd entry. */
@@ -258,7 +258,7 @@ if (  !ob->cmd_uid_set
 if (!ob->cmd_gid_set)
   if (ob->expand_cmd_gid)
     {
-    if (route_find_expanded_group(ob->expand_cmd_gid, rblock->name,
+    if (route_find_expanded_group(ob->expand_cmd_gid, rblock->drinst.name,
         US"router", &gid, &(addr->message)))
       return DEFER;
     }
@@ -267,7 +267,7 @@ if (!ob->cmd_gid_set)
   else
     {
     addr->message = string_sprintf("command_user set without command_group "
-      "for %s router", rblock->name);
+      "for %s router", rblock->drinst.name);
     return DEFER;
     }


@@ -305,7 +305,7 @@ if ((pid = child_open_uid(argvptr, NULL, 0077, puid, pgid, &fd_in, &fd_out,
               current_directory, TRUE, US"queryprogram-cmd")) < 0)
   {
   addr->message = string_sprintf("%s router couldn't create child process: %s",
-    rblock->name, strerror(errno));
+    rblock->drinst.name, strerror(errno));
   return DEFER;
   }


@@ -320,22 +320,22 @@ if ((rc = child_close(pid, ob->timeout)) != 0)
   {
   if (rc > 0)
     addr->message = string_sprintf("%s router: command returned non-zero "
-      "code %d", rblock->name, rc);
+      "code %d", rblock->drinst.name, rc);


   else if (rc == -256)
     {
     addr->message = string_sprintf("%s router: command timed out",
-      rblock->name);
+      rblock->drinst.name);
     killpg(pid, SIGKILL);       /* Kill the whole process group */
     }


   else if (rc == -257)
     addr->message = string_sprintf("%s router: wait() failed: %s",
-      rblock->name, strerror(errno));
+      rblock->drinst.name, strerror(errno));


   else
     addr->message = string_sprintf("%s router: command killed by signal %d",
-      rblock->name, -rc);
+      rblock->drinst.name, -rc);


   return DEFER;
   }
@@ -350,7 +350,7 @@ len = read(fd_out, buffer, sizeof(buffer) - 1);
 if (len <= 0)
   {
   addr->message = string_sprintf("%s router: command failed to return data",
-    rblock->name);
+    rblock->drinst.name);
   return DEFER;
   }


@@ -394,7 +394,7 @@ if (strcmpic(rword, US"REDIRECT") == 0)
     &addr->message,              /* where to put messages */
     NULL,                        /* don't skip syntax errors */
     &filtertype,                 /* not used; will always be FILTER_FORWARD */
-    string_sprintf("%s router", rblock->name));
+    string_sprintf("%s router", rblock->drinst.name));


   switch (rc)
     {
@@ -456,7 +456,7 @@ if (strcmpic(rword, US"accept") != 0)
   else if (strcmpic(rword, US"defer") != 0)
     {
     addr->message = string_sprintf("bad command yield: %s %s", rword, rdata);
-    log_write(0, LOG_PANIC, "%s router: %s", rblock->name, addr->message);
+    log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message);
     }
   return DEFER;
   }
@@ -479,7 +479,7 @@ if ((s = expand_getkeyed(US"transport", rdata)) && *s)
     {
     addr->message = string_sprintf("unknown transport name %s yielded by "
       "command", s);
-    log_write(0, LOG_PANIC, "%s router: %s", rblock->name, addr->message);
+    log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message);
     return DEFER;
     }
   addr->transport = transport;
@@ -492,7 +492,7 @@ the last argument not being NULL. */
 else
   {
   if (!rf_get_transport(rblock->transport_name, &rblock->transport, addr,
-       rblock->name, US"transport"))
+       rblock->drinst.name, US"transport"))
     return DEFER;
   addr->transport = rblock->transport;
   }
@@ -512,7 +512,7 @@ if ((s = expand_getkeyed(US"hosts", rdata)) && *s)
       {
       addr->message = string_sprintf("bad lookup type \"%s\" yielded by "
         "command", ss);
-      log_write(0, LOG_PANIC, "%s router: %s", rblock->name, addr->message);
+      log_write(0, LOG_PANIC, "%s router: %s", rblock->drinst.name, addr->message);
       return DEFER;
       }
     }
diff --git a/src/src/routers/queryprogram.h b/src/src/routers/queryprogram.h
index f2cff1dab..67c0ba7bc 100644
--- a/src/src/routers/queryprogram.h
+++ b/src/src/routers/queryprogram.h
@@ -36,6 +36,6 @@ extern int queryprogram_router_entry(router_instance *, address_item *,
   struct passwd *, int, address_item **, address_item **,
   address_item **, address_item **);


-extern void queryprogram_router_init(router_instance *);
+extern void queryprogram_router_init(driver_instance *);

/* End of routers/queryprogram.h */
diff --git a/src/src/routers/redirect.c b/src/src/routers/redirect.c
index 4da658781..97e609413 100644
--- a/src/src/routers/redirect.c
+++ b/src/src/routers/redirect.c
@@ -112,7 +112,7 @@ int redirect_router_options_count =

/* Dummy entries */
redirect_router_options_block redirect_router_option_defaults = {0};
-void redirect_router_init(router_instance *rblock) {}
+void redirect_router_init(driver_instance *rblock) {}
int redirect_router_entry(router_instance *rblock, address_item *addr,
struct passwd *pw, int verify, address_item **addr_local,
address_item **addr_remote, address_item **addr_new,
@@ -141,17 +141,19 @@ redirect_router_options_block redirect_router_option_defaults = {
/* Called for each instance, after its options have been read, to enable
consistency checks to be done, or anything else that needs to be set up. */

-void redirect_router_init(router_instance *rblock)
+void
+redirect_router_init(driver_instance * r)
{
-redirect_router_options_block *ob =
- (redirect_router_options_block *)(rblock->options_block);
+router_instance * rblock = (router_instance *)r;
+redirect_router_options_block * ob =
+ (redirect_router_options_block *)(r->options_block);

/* Either file or data must be set, but not both */

 if ((ob->file == NULL) == (ob->data == NULL))
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
     "%sone of \"file\" or \"data\" must be specified",
-    rblock->name, (ob->file == NULL)? "" : "only ");
+    r->name, ob->file ? "only " : "");


 /* Onetime aliases can only be real addresses. Headers can't be manipulated.
 The combination of one_time and unseen is not allowed. We can't check the
@@ -164,10 +166,10 @@ if (ob->one_time)
   if (rblock->extra_headers || rblock->remove_headers)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
       "\"headers_add\" and \"headers_remove\" are not permitted with "
-      "\"one_time\"", rblock->name);
+      "\"one_time\"", r->name);
   if (rblock->unseen || rblock->expand_unseen)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
-      "\"unseen\" may not be used with \"one_time\"", rblock->name);
+      "\"unseen\" may not be used with \"one_time\"", r->name);
   }


 /* The defaults for check_owner and check_group depend on other settings. The
@@ -188,7 +190,7 @@ if (ob->check_group == TRUE_UNSET)
 if (ob->qualify_domain && ob->qualify_preserve_domain)
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
     "only one of \"qualify_domain\" or \"qualify_preserve_domain\" must be set",
-    rblock->name);
+    r->name);


/* If allow_filter is set, either user or check_local_user must be set. */

@@ -198,7 +200,7 @@ if (!rblock->check_local_user &&
     (ob->bit_options & RDO_FILTER) != 0)
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s router:\n  "
     "\"user\" or \"check_local_user\" must be set with \"allow_filter\"",
-    rblock->name);
+    r->name);
 }



@@ -275,8 +277,8 @@ add_generated(router_instance *rblock, address_item **addr_new,
address_item *addr, address_item *generated,
address_item_propagated *addr_prop, ugid_block *ugidptr, struct passwd *pw)
{
-redirect_router_options_block *ob =
- (redirect_router_options_block *)(rblock->options_block);
+redirect_router_options_block * ob =
+ (redirect_router_options_block *)(rblock->drinst.options_block);

 while (generated)
   {
@@ -288,7 +290,7 @@ while (generated)
   next->start_router = rblock->redirect_router;
   if (addr->child_count == USHRT_MAX)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
-      "child addresses for <%s>", rblock->name, USHRT_MAX, addr->address);
+      "child addresses for <%s>", rblock->drinst.name, USHRT_MAX, addr->address);
   addr->child_count++;


   next->next = *addr_new;
@@ -370,7 +372,7 @@ while (generated)
       address_pipe = next->address;
       GET_OPTION("pipe_transport");
       if (rf_get_transport(ob->pipe_transport_name, &ob->pipe_transport,
-          next, rblock->name, US"pipe_transport"))
+          next, rblock->drinst.name, US"pipe_transport"))
         next->transport = ob->pipe_transport;
       address_pipe = NULL;
       }
@@ -378,7 +380,7 @@ while (generated)
       {
       GET_OPTION("reply_transport");
       if (rf_get_transport(ob->reply_transport_name, &ob->reply_transport,
-          next, rblock->name, US"reply_transport"))
+          next, rblock->drinst.name, US"reply_transport"))
         next->transport = ob->reply_transport;
       }
     else  /* must be file or directory */
@@ -389,7 +391,7 @@ while (generated)
         {
     GET_OPTION("directory_transport");
         if (rf_get_transport(ob->directory_transport_name,
-            &(ob->directory_transport), next, rblock->name,
+            &ob->directory_transport, next, rblock->drinst.name,
             US"directory_transport"))
           next->transport = ob->directory_transport;
         }
@@ -397,7 +399,7 @@ while (generated)
     {
     GET_OPTION("file_transport");
         if (rf_get_transport(ob->file_transport_name, &ob->file_transport,
-            next, rblock->name, US"file_transport"))
+            next, rblock->drinst.name, US"file_transport"))
           next->transport = ob->file_transport;
     }


@@ -414,7 +416,7 @@ while (generated)
   DEBUG(D_route)
     {
     debug_printf("%s router generated %s\n  %serrors_to=%s transport=%s\n",
-      rblock->name,
+      rblock->drinst.name,
       next->address,
       testflag(next, af_pfr)? "pipe, file, or autoreply\n  " : "",
       next->prop.errors_address,
@@ -478,8 +480,8 @@ int redirect_router_entry(
   address_item **addr_new,        /* put new addresses on here */
   address_item **addr_succeed)    /* put old address here on success */
 {
-redirect_router_options_block *ob =
-  (redirect_router_options_block *)(rblock->options_block);
+redirect_router_options_block * ob =
+  (redirect_router_options_block *)(rblock->drinst.options_block);
 address_item *generated = NULL;
 const uschar *save_qualify_domain_recipient = qualify_domain_recipient;
 uschar *discarded = US"discarded";
@@ -525,13 +527,13 @@ can't be found in the password file. Other errors set the freezing bit. */


if (!rf_get_ugid(rblock, addr, &ugid)) return DEFER;

-if (!ugid.uid_set && pw != NULL)
+if (!ugid.uid_set && pw)
{
ugid.uid = pw->pw_uid;
ugid.uid_set = TRUE;
}

-if (!ugid.gid_set && pw != NULL)
+if (!ugid.gid_set && pw)
{
ugid.gid = pw->pw_gid;
ugid.gid_set = TRUE;
@@ -575,8 +577,8 @@ sieve.enotify_mailto_owner = ob->sieve_enotify_mailto_owner;

frc = rda_interpret(&redirect, options, ob->include_directory, &sieve, &ugid,
&generated, &addr->message, ob->skip_syntax_errors ? &eblock : NULL,
- &filtertype, string_sprintf("%s router (recipient is %s)", rblock->name,
- addr->address));
+ &filtertype, string_sprintf("%s router (recipient is %s)",
+ rblock->drinst.name, addr->address));

qualify_domain_recipient = save_qualify_domain_recipient;

@@ -701,7 +703,7 @@ dealing with it, the router declines. */
 if (eblock != NULL)
   {
   if (!moan_skipped_syntax_errors(
-        rblock->name,                            /* For message content */
+        rblock->drinst.name,             /* For message content */
         eblock,                                  /* Ditto */
         (verify != v_none || f.address_test_mode)?
           NULL : ob->syntax_errors_to,           /* Who to mail */
@@ -738,7 +740,7 @@ if (frc == FF_DELIVERED)
   if (generated == NULL && verify == v_none && !f.address_test_mode)
     {
     log_write(0, LOG_MAIN, "=> %s <%s> R=%s", discarded, addr->address,
-      rblock->name);
+      rblock->drinst.name);
     yield = DISCARD;
     }
   }
@@ -769,7 +771,7 @@ else
   next->prop = addr_prop;


   DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
-    rblock->name,
+    rblock->drinst.name,
     next->address,
     (addr_prop.errors_address != NULL)? "  errors to " : "",
     (addr_prop.errors_address != NULL)? addr_prop.errors_address : US"",
diff --git a/src/src/routers/redirect.h b/src/src/routers/redirect.h
index 86c24d80c..f36db1600 100644
--- a/src/src/routers/redirect.h
+++ b/src/src/routers/redirect.h
@@ -69,6 +69,6 @@ extern int redirect_router_entry(router_instance *, address_item *,
   struct passwd *, int, address_item **, address_item **,
   address_item **, address_item **);


-extern void redirect_router_init(router_instance *);
+extern void redirect_router_init(driver_instance *);

 /* End of routers/redirect.h */
diff --git a/src/src/routers/rf_get_errors_address.c b/src/src/routers/rf_get_errors_address.c
index 6f8f7c7c3..6593ef2b6 100644
--- a/src/src/routers/rf_get_errors_address.c
+++ b/src/src/routers/rf_get_errors_address.c
@@ -53,7 +53,7 @@ if (!(s = expand_string(rblock->errors_to)))
     return OK;
     }
   addr->message = string_sprintf("%s router failed to expand \"%s\": %s",
-    rblock->name, rblock->errors_to, expand_string_message);
+    rblock->drinst.name, rblock->errors_to, expand_string_message);
   return DEFER;
   }


diff --git a/src/src/routers/rf_get_munge_headers.c b/src/src/routers/rf_get_munge_headers.c
index 58b5bc7ad..a9cffab72 100644
--- a/src/src/routers/rf_get_munge_headers.c
+++ b/src/src/routers/rf_get_munge_headers.c
@@ -50,7 +50,7 @@ if (rblock->extra_headers)
     {
     addr->message = string_sprintf(
       "%s router failed to expand add_headers item \"%s\": %s",
-      rblock->name, t, expand_string_message);
+      rblock->drinst.name, t, expand_string_message);
     return DEFER;
     }
       }
@@ -105,7 +105,7 @@ if (rblock->remove_headers)
     {
     addr->message = string_sprintf(
       "%s router failed to expand remove_headers item \"%s\": %s",
-      rblock->name, t, expand_string_message);
+      rblock->drinst.name, t, expand_string_message);
     return DEFER;
     }
       }
diff --git a/src/src/routers/rf_get_ugid.c b/src/src/routers/rf_get_ugid.c
index cefe527a5..a0197b409 100644
--- a/src/src/routers/rf_get_ugid.c
+++ b/src/src/routers/rf_get_ugid.c
@@ -41,20 +41,22 @@ ugid->initgroups = rblock->initgroups;
 /* If there is no fixed uid set, see if there's a dynamic one that can
 be expanded and possibly looked up. */


-if (!ugid->uid_set && rblock->expand_uid != NULL)
+if (!ugid->uid_set && rblock->expand_uid)
   {
-  if (route_find_expanded_user(rblock->expand_uid, rblock->name, US"router",
-    &upw, &(ugid->uid), &(addr->message))) ugid->uid_set = TRUE;
-  else return FALSE;
+  if (!route_find_expanded_user(rblock->expand_uid, rblock->drinst.name,
+                  US"router", &upw, &ugid->uid, &addr->message))
+    return FALSE;
+  ugid->uid_set = TRUE;
   }


/* Likewise for the gid */

-if (!ugid->gid_set && rblock->expand_gid != NULL)
+if (!ugid->gid_set && rblock->expand_gid)
   {
-  if (route_find_expanded_group(rblock->expand_gid, rblock->name, US"router",
-    &(ugid->gid), &(addr->message))) ugid->gid_set = TRUE;
-  else return FALSE;
+  if (!route_find_expanded_group(rblock->expand_gid, rblock->drinst.name,
+                  US"router", &ugid->gid, &addr->message))
+    return FALSE;
+  ugid->gid_set = TRUE;
   }


/* If a uid is set, then a gid must also be available; use one from the passwd
@@ -62,7 +64,7 @@ lookup if it happened. */

 if (ugid->uid_set && !ugid->gid_set)
   {
-  if (upw != NULL)
+  if (upw)
     {
     ugid->gid = upw->pw_gid;
     ugid->gid_set = TRUE;
@@ -70,7 +72,7 @@ if (ugid->uid_set && !ugid->gid_set)
   else
     {
     addr->message = string_sprintf("user set without group for %s router",
-      rblock->name);
+      rblock->drinst.name);
     return FALSE;
     }
   }
diff --git a/src/src/routers/rf_lookup_hostlist.c b/src/src/routers/rf_lookup_hostlist.c
index f10ff5921..54a614e05 100644
--- a/src/src/routers/rf_lookup_hostlist.c
+++ b/src/src/routers/rf_lookup_hostlist.c
@@ -174,7 +174,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h)
       {
       DEBUG(D_route)
         debug_printf("%s router timed out and pass_on_timeout set\n",
-          rblock->name);
+          rblock->drinst.name);
       return PASS;
       }
     addr->message = string_sprintf("host lookup for %s did not complete "
@@ -199,7 +199,7 @@ for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h)
     addr->basic_errno = ERRNO_UNKNOWNHOST;
     addr->message =
       string_sprintf("lookup of host \"%s\" failed in %s router%s",
-        h->name, rblock->name,
+        h->name, rblock->drinst.name,
         f.host_find_failed_syntax? ": syntax error in name" : "");


     if (hff_code == hff_defer) return DEFER;
diff --git a/src/src/structs.h b/src/src/structs.h
index 95a1c1099..ddebd18d5 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -130,9 +130,9 @@ three, the layout of the start of the blocks is kept the same, and represented
 by the generic structures driver_info and driver_instance. */


 typedef struct driver_instance {
-  struct driver_instance *next;
+  void   *next;
   uschar *name;                   /* Instance name */
-  struct driver_info *info;       /* Points to info for this driver */
+  void   *info;              /* Points to info for this driver */
   void   *options_block;          /* Pointer to private options */


   uschar *driver_name;            /* All start with this generic option */
@@ -148,7 +148,7 @@ typedef struct driver_info {
   void   *options_block;          /* Points to default private block */
   int     options_len;            /* Length of same in bytes */
   void  (*init)(                  /* Initialization entry point */
-    struct driver_instance *);
+      struct driver_instance *);
 } driver_info;



@@ -286,13 +286,7 @@ typedef struct {
/* Structure for holding information about the configured routers. */

 typedef struct router_instance {
-  struct router_instance *next;
-  uschar *name;
-  struct router_info *info;
-  void   *options_block;          /* Pointer to private options */
-  uschar *driver_name;            /* Must be first */
-  const uschar *srcfile;
-  int      srcline;
+  driver_instance drinst;


   uschar *address_data;           /* Arbitrary data */
 #ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -369,18 +363,12 @@ typedef struct router_instance {
 } router_instance;



-/* Structure for holding information about a type of router. The first six
-fields must match driver_info above. */
+/* Structure for holding information about a type of router. The first element
+must be a struct driver_info, to match auths and transports. */

 typedef struct router_info {
-  uschar *driver_name;
-  optionlist *options;            /* Table of private options names */
-  int    *options_count;          /* -> Number of entries in table */
-  void   *options_block;          /* Points to default private block */
-  int     options_len;            /* Length of same in bytes */
-  void (*init)(                   /* Initialization function */
-    struct router_instance *);
-/****/
+  driver_info drinfo;
+
   int (*code)(                    /* Main entry point */
     router_instance *,
     struct address_item *,
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index 03de9dcad..f80afbc0a 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -672,7 +672,8 @@ deferred_event_raise(address_item * addr, host_item * host, uschar * evstr)
 {
 uschar * action = addr->transport->event_action;
 const uschar * save_domain, * save_local;
-uschar * save_rn, * save_tn;
+const uschar * save_rn;
+uschar * save_tn;


 if (!action)
   return;
@@ -687,7 +688,7 @@ deliver_host_address = string_copy(host->address);
 deliver_host_port =    host->port == PORT_NONE ? 25 : host->port;
 event_defer_errno =    addr->basic_errno;


-router_name =    addr->router->name;
+router_name =    addr->router->drinst.name;
 transport_name = addr->transport->name;
 deliver_domain = addr->domain;
 deliver_localpart = addr->local_part;
diff --git a/src/src/verify.c b/src/src/verify.c
index 25fc700f9..ad6b0afaf 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -2235,7 +2235,7 @@ for (addr_list = addr_local, i = 0; i < 2; addr_list = addr_remote, i++)
     /* Show router, and transport */


     fprintf(fp, "router = %s, transport = %s\n",
-      addr->router->name, tp ? tp->name : US"unset");
+      addr->router->drinst.name, tp ? tp->name : US"unset");


     /* Show any hosts that are set up by a router unless the transport
     is going to override them; fiddle a bit to get a nice format. */


--
## subscription configuration (requires account):
## https://lists.exim.org/mailman3/postorius/lists/exim-cvs.lists.exim.org/
## unsubscribe (doesn't require an account):
## exim-cvs-unsubscribe@???
## Exim details at http://www.exim.org/
## Please use the Wiki with this list - http://wiki.exim.org/