+/* Add a driver info struct to a list. */
+
+void
+add_driver_info(driver_info ** drlist_p, const driver_info * newent,
+ size_t size)
+{
+driver_info * listent = store_get(size, newent);
+memcpy(listent, newent, size);
+listent->next = *drlist_p;
+*drlist_p= listent;
+}
+
/*************************************************
* Initialize one driver *
*************************************************/
Arguments:
d pointer to driver instance block, with generic
options filled in
- drivers_available vector of available drivers
+ info_anchor list of available drivers
size_of_info size of each block in drivers_available
- class class of driver, for error message
+ class class of driver
Returns: pointer to the driver info block
*/
static driver_info *
-init_driver(driver_instance * d, driver_info * drivers_available,
+init_driver(driver_instance * d, driver_info ** info_anchor,
int size_of_info, const uschar * class)
{
-/*XXX if dynamic, the _info entry will be here but code may or may not
-be loaded. How to tell? What's the entry point? init call?
-Currently that is IN the _info entry.
+/*XXX if dynamic, the _info entry will not be here yet.
For lookups it does it by pulling the info entry out of the dlopen()d
file (for dynamic) or direct from the lookup .o file (for static).
#ifdef old
/*XXX walk the old array */
-for (driver_info * dd = drivers_available; dd->driver_name[0] != 0;
- dd = (driver_info *)((US dd) + size_of_info))
+for (driver_info * di= *info_anchor; di->driver_name[0] != 0;
+ di= (driver_info *)((US di) + size_of_info))
#endif
-for (driver_info * dd = drivers_available; dd; dd = dd->next)
- if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
+driver_info * di;
+int len;
+DIR * dd;
+
+/* First scan the list of statically-built drivers. */
+
+for (di = *info_anchor; di; di = di->next)
+ if (Ustrcmp(d->driver_name, di->driver_name) == 0)
+ goto found;
+
+#ifdef LOOKUP_MODULE_DIR
+/* Potentially a loadable module. Look for a file with the right name. */
+
+if (!(dd = exim_opendir(CUS LOOKUP_MODULE_DIR)))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "Couldn't open %s: not loading driver modules\n", LOOKUP_MODULE_DIR);
+ }
+else
+ {
+ uschar * fname = string_sprintf("%s_%s." DYNLIB_FN_EXT, d->driver_name, class), * sname;
+ const char * errormsg;
+
+ DEBUG(D_any) debug_printf("Loading %s %s driver from %s\n",
+ d->driver_name, class, LOOKUP_MODULE_DIR);
+
+ for(struct dirent * ent; ent = readdir(dd); ) if (Ustrcmp(ent->d_name, fname) == 0)
{
- int len = dd->options_len;
- d->info = dd;
- d->options_block = store_get_perm(len, GET_UNTAINTED);
- memcpy(d->options_block, dd->options_block, len);
- for (int i = 0; i < *dd->options_count; i++)
- dd->options[i].type &= ~opt_set;
- return dd;
+ void * dl = dlopen(CS string_sprintf(LOOKUP_MODULE_DIR "/%s", fname), RTLD_NOW);
+ static driver_magics dm[] = {
+ { ROUTER_MAGIC, US"router" },
+ { TRANSPORT_MAGIC, US"transport" },
+ { AUTH_MAGIC, US"auth" },
+ };
+
+ if (!dl)
+ {
+ errormsg = dlerror();
+ log_write(0, LOG_MAIN|LOG_PANIC, "Error loading %s %s driver: %s\n",
+ d->driver_name, class, errormsg);
+ break;
+ }
+ (void) dlerror(); /* cf. comment in init_lookup_list() */
+
+ di = (driver_info *) dlsym(dl, CS string_sprintf("_%s_info", class));
+ if ((errormsg = dlerror()))
+ {
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s does not appear to be a %s module (%s)\n", fname, class, errormsg);
+ dlclose(dl);
+ break;
+ }
+ for(driver_magics * dmp = dm; dmp < dm + nelem(dm); dmp++)
+ if(Ustrcmp(dmp->class, class) == 0 && dmp->magic == di->dyn_magic)
+ {
+ add_driver_info(info_anchor, di, size_of_info);
+ DEBUG(D_any) debug_printf("Loaded %s %s\n", d->driver_name, class);
+ closedir(dd);
+ goto found;
+ }
+
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "%s module %s is not compatible with this version of Exim\n",
+ class, d->driver_name);
+ dlclose(dl);
+ break;
}
+ closedir(dd);
+ }
+#endif /* LOOKUP_MODULE_DIR */
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"%s %s: cannot find %s driver \"%s\"", class, d->name, class, d->driver_name);
-return NULL; /* never obeyed */
+found:
+
+len = di->options_len;
+d->info = di;
+d->options_block = store_get_perm(len, GET_UNTAINTED);
+memcpy(d->options_block, di->options_block, len);
+for (int i = 0; i < *di->options_count; i++)
+ di->options[i].type &= ~opt_set;
+return di;
}
Arguments:
anchor &routers, &transports, &auths
- drivers_available available drivers
+ info_anchor available drivers
size_of_info size of each info block
instance_default points to default data for an instance
instance_size size of instance block
void
readconf_driver_init(
driver_instance ** anchor,
- driver_info * drivers_available, /*XXX now list not array */
+ driver_info ** info_anchor, /*XXX now list not array, static only so far */
int size_of_info,
void * instance_default,
int instance_size,
driver_optionlist_count, d, NULL))
{
if (!d->info && d->driver_name)
- init_driver(d, drivers_available, size_of_info, class);
+ init_driver(d, info_anchor, size_of_info, class);
}
/* Handle private options - pass the generic block because some may
readconf_driver_init((driver_instance **)&auths, /* chain anchor */
- (driver_info *)auths_available_newlist, /* available drivers */
+ (driver_info **)&auths_available_newlist, /* available drivers */
sizeof(auth_info), /* size of info block */
&auth_defaults, /* default values for generic options */
sizeof(auth_instance), /* size of instance block */
* Initialize router list *
*************************************************/
-/*XXX will likely want to rename to generic */
-
-static void
-add_router(driver_info ** drlist_p, const driver_info * newent, size_t size)
-{
-driver_info * listent = store_get(size, newent);
-memcpy(listent, newent, size);
-listent->next = *drlist_p;
-*drlist_p= listent;
-}
-
/* Read the routers section of the configuration file, and set up a chain of
router instances according to its contents. Each router has generic options and
may also have its own private options. This function is only ever called when
extern router_info redirect_router_info;
extern router_info queryprogram_router_info;
- /*XXX this addsonly the statics. We can't get the dynamics as they
+ /*XXX this adds only the statics. We can't get the dynamics as they
are not linked. Until dlopen(), when we can use dlsym(). So the discovery
is by the file exitence, via the filename pattern. */
/*XXX TODO: move the info structs to individual driver files */
#if defined(ROUTER_ACCEPT) && ROUTER_ACCEPT!=2
- add_router(anchor, &accept_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &accept_router_info.drinfo, sizeof(router_info));
#endif
#if defined(ROUTER_DNSLOOKUP) && ROUTER_DNSLOOKUP!=2
- add_router(anchor, &dnslookup_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &dnslookup_router_info.drinfo, sizeof(router_info));
#endif
# if defined(ROUTER_IPLITERAL) && ROUTER_IPLITERAL!=2
- add_router(anchor, &ipliteral_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &ipliteral_router_info.drinfo, sizeof(router_info));
#endif
#if defined(ROUTER_IPLOOKUP) && ROUTER_IPLOOKUP!=2
- add_router(anchor, &iplookup_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &iplookup_router_info.drinfo, sizeof(router_info));
#endif
#if defined(ROUTER_MANUALROUTE) && ROUTER_MANUALROUTE!=2
- add_router(anchor, &manualroute_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &manualroute_router_info.drinfo, sizeof(router_info));
#endif
#if defined(ROUTER_REDIRECT) && ROUTER_REDIRECT!=2
- add_router(anchor, &redirect_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &redirect_router_info.drinfo, sizeof(router_info));
#endif
#if defined(ROUTER_QUERYPROGRAM) && ROUTER_QUERYPROGRAM!=2
- add_router(anchor, &queryprogram_router_info.drinfo, sizeof(router_info));
+ add_driver_info(anchor, &queryprogram_router_info.drinfo, sizeof(router_info));
#endif
}
store_pool = old_pool;
/*XXX this does the config file "routers" section reading */
readconf_driver_init((driver_instance **)&routers, /* chain anchor */
- (driver_info *)routers_available_newlist, /* available drivers */
+ (driver_info **)&routers_available_newlist, /* available drivers */
sizeof(router_info), /* size of info blocks */
&router_defaults, /* default values for generic options */
sizeof(router_instance), /* size of instance block */