]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.12-20140516-nonprod
authorWietse Venema <wietse@porcupine.org>
Fri, 16 May 2014 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 19 May 2014 14:29:53 +0000 (10:29 -0400)
17 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/makedefs
postfix/src/fsstone/Makefile.in
postfix/src/global/Makefile.in
postfix/src/global/dynamicmaps.c [new file with mode: 0644]
postfix/src/global/dynamicmaps.h [moved from postfix/src/util/dynamicmaps.h with 68% similarity]
postfix/src/global/mail_version.h
postfix/src/global/mkmap.h
postfix/src/global/mkmap_open.c
postfix/src/pipe/pipe.c
postfix/src/smtpstone/Makefile.in
postfix/src/util/Makefile.in
postfix/src/util/dict.h
postfix/src/util/dict_db.c
postfix/src/util/dict_open.c
postfix/src/util/dynamicmaps.c [deleted file]

index 879fd42be8062c6a3ab08d986f83dad5af4f9c84..469ceb812a117b8224078e0cf57a36c255f61b5f 100644 (file)
@@ -74,7 +74,6 @@
 -TDICT_DB
 -TDICT_DBM
 -TDICT_DEBUG
--TDICT_DL_INFO
 -TDICT_ENV
 -TDICT_FAIL
 -TDICT_HT
@@ -86,6 +85,8 @@
 -TDICT_NIS
 -TDICT_NISPLUS
 -TDICT_NODE
+-TDICT_OPEN_EXTEND_FN
+-TDICT_OPEN_FN
 -TDICT_OPEN_INFO
 -TDICT_OWNER
 -TDICT_PCRE
 -TDSN_FILTER
 -TDSN_SPLIT
 -TDSN_STAT
+-TDYMAP_INFO
 -TEC_GROUP
 -TEC_KEY
 -TEDIT_FILE
 -TMKMAP
 -TMKMAP_DB
 -TMKMAP_DBM
+-TMKMAP_OPEN_EXTEND_FN
+-TMKMAP_OPEN_FN
 -TMKMAP_OPEN_INFO
 -TMKMAP_SDBM
 -TMSG_STATS
index 6e997a50c7906d78219bf413a8624e224be1bbe9..64f15530d5c66cc5974d9798b19ea3c92dbd85d2 100644 (file)
@@ -19721,7 +19721,7 @@ Apologies for any names omitted.
        poorly reflected their purpose. "DEAD" is replaced with
        "FORBIDDEN" (no I/O allowed) and "BAD" is replaced with
        "THROTTLED" (anything that causes the queue manager to back
-       off from some destination). Files: smtp.h, smtp_coonnect.c,
+       off from some destination). Files: smtp.h, smtp_connect.c,
        smtp_proto.c, smtp_trouble.c.
 
        Cleanup: enable SMTP connection cache lookup by destination
@@ -19764,3 +19764,23 @@ Apologies for any names omitted.
        print/view README-format files are in the INSTALL file).
 
        Documentation: updated INSTALL instructions and RELEASE_NOTES.
+
+20140512
+
+       Portability: Berkeley DB6 support. File: util/dict_db.c.
+
+20140514
+
+       Cleanup: replace #ifdefs with hard-coded dynamicmaps calls
+       with an extension mechanism. Files: util/dict.h, util/dict_open.c,
+       global/dynamicmaps.[hc], global/mkmap.h, global/mkmap_open.c.
+
+20140515
+
+       Bugfix (introduced: 20140320): missing initialization.
+       Viktor Dukhovni. File pipe/pipe.c.
+
+       Cleanup: mkmap_open() now caches a dynamically-loaded
+       function. This is useful because postmap/postalias may open
+       the same database type multiple times. Files: global/mkmap.h,
+       global/mkmap_open.c.
index 24af0dd14b5367c70b88863917801a38a997403d..c1297fae3c82e4461aade376306981bbbc54fc57 100644 (file)
@@ -683,6 +683,9 @@ queue_directory_macro=DEF_QUEUE_DIR
 sendmail_path_macro=DEF_SENDMAIL_PATH
 shlib_directory_macro=DEF_SHLIB_DIR
 
+# shlib_directory is checked here because "no" is not a good answer.
+# Instead, build with "shared=no".
+
 for parm_name in command_directory config_directory daemon_directory \
        data_directory mailq_path newaliases_path \
        queue_directory sendmail_path shlib_directory
index 2456448efc46b65125983a044ee541535715b2dd..564a3009a7e9f673df752ac784f2dc49c6da4f45 100644 (file)
@@ -21,7 +21,7 @@ Makefile: Makefile.in
        cat ../../conf/makedefs.out $? >$@
 
 fsstone: fsstone.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ fsstone.o $(LIBS) $(SYSLIBS)
+       $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ fsstone.o $(LIBS) $(SYSLIBS)
 
 test:  $(TESTPROG)
 
index 306b92b240dc0880c028c91d9b4db5ce41d75e09..9b252c9a8a85ba55102fd479187a1400e602eab6 100644 (file)
@@ -32,7 +32,7 @@ SRCS  = abounce.c anvil_clnt.c been_here.c bounce.c bounce_log.c \
        match_service.c mail_conf_nint.c addr_match_list.c mail_conf_nbool.c \
        smtp_reply_footer.c safe_ultostr.c verify_sender_addr.c \
        dict_memcache.c mail_version.c memcache_proto.c server_acl.c \
-       mkmap_fail.c haproxy_srvr.c dsn_filter.c
+       mkmap_fail.c haproxy_srvr.c dsn_filter.c dynamicmaps.c
 OBJS   = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        canon_addr.o cfg_parser.o cleanup_strerror.o cleanup_strflags.o \
        clnt_stream.o conv_time.o db_common.o debug_peer.o debug_process.o \
@@ -66,7 +66,7 @@ OBJS  = abounce.o anvil_clnt.o been_here.o bounce.o bounce_log.o \
        match_service.o mail_conf_nint.o addr_match_list.o mail_conf_nbool.o \
        smtp_reply_footer.o safe_ultostr.o verify_sender_addr.o \
        dict_memcache.o mail_version.o memcache_proto.o server_acl.o \
-       mkmap_fail.o haproxy_srvr.o dsn_filter.o
+       mkmap_fail.o haproxy_srvr.o dsn_filter.o dynamicmaps.o
 HDRS   = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        canon_addr.h cfg_parser.h cleanup_user.h clnt_stream.h config.h \
        conv_time.h db_common.h debug_peer.h debug_process.h defer.h \
@@ -93,7 +93,7 @@ HDRS  = abounce.h anvil_clnt.h been_here.h bounce.h bounce_log.h \
        fold_addr.h header_body_checks.h data_redirect.h match_service.h \
        addr_match_list.h smtp_reply_footer.h safe_ultostr.h \
        verify_sender_addr.h dict_memcache.h memcache_proto.h server_acl.h \
-       haproxy_srvr.h dsn_filter.h
+       haproxy_srvr.h dsn_filter.h dynamicmaps.h
 TESTSRC        = rec2stream.c stream2rec.c recdump.c
 DEFS   = -I. -I$(INC_DIR) -D$(SYSTYPE)
 CFLAGS = $(DEBUG) $(OPT) $(DEFS)
@@ -1054,6 +1054,21 @@ dsn_util.o: ../../include/vbuf.h
 dsn_util.o: ../../include/vstring.h
 dsn_util.o: dsn_util.c
 dsn_util.o: dsn_util.h
+dynamicmaps.o: ../../include/argv.h
+dynamicmaps.o: ../../include/dict.h
+dynamicmaps.o: ../../include/load_lib.h
+dynamicmaps.o: ../../include/msg.h
+dynamicmaps.o: ../../include/mvect.h
+dynamicmaps.o: ../../include/myflock.h
+dynamicmaps.o: ../../include/mymalloc.h
+dynamicmaps.o: ../../include/sys_defs.h
+dynamicmaps.o: ../../include/vbuf.h
+dynamicmaps.o: ../../include/vstream.h
+dynamicmaps.o: ../../include/vstring.h
+dynamicmaps.o: ../../include/vstring_vstream.h
+dynamicmaps.o: dynamicmaps.c
+dynamicmaps.o: dynamicmaps.h
+dynamicmaps.o: mkmap.h
 ehlo_mask.o: ../../include/name_mask.h
 ehlo_mask.o: ../../include/sys_defs.h
 ehlo_mask.o: ../../include/vbuf.h
@@ -1380,7 +1395,6 @@ mail_date.o: mail_date.c
 mail_date.o: mail_date.h
 mail_dict.o: ../../include/argv.h
 mail_dict.o: ../../include/dict.h
-mail_dict.o: ../../include/dynamicmaps.h
 mail_dict.o: ../../include/msg.h
 mail_dict.o: ../../include/myflock.h
 mail_dict.o: ../../include/mymalloc.h
@@ -1395,6 +1409,7 @@ mail_dict.o: dict_mysql.h
 mail_dict.o: dict_pgsql.h
 mail_dict.o: dict_proxy.h
 mail_dict.o: dict_sqlite.h
+mail_dict.o: dynamicmaps.h
 mail_dict.o: mail_dict.c
 mail_dict.o: mail_dict.h
 mail_dict.o: mail_params.h
@@ -1705,10 +1720,10 @@ mkmap_open.o: ../../include/dict.h
 mkmap_open.o: ../../include/dict_cdb.h
 mkmap_open.o: ../../include/dict_db.h
 mkmap_open.o: ../../include/dict_dbm.h
-mkmap_open.o: ../../include/dynamicmaps.h
 mkmap_open.o: ../../include/dict_fail.h
 mkmap_open.o: ../../include/dict_lmdb.h
 mkmap_open.o: ../../include/dict_sdbm.h
+mkmap_open.o: ../../include/htable.h
 mkmap_open.o: ../../include/msg.h
 mkmap_open.o: ../../include/myflock.h
 mkmap_open.o: ../../include/mymalloc.h
diff --git a/postfix/src/global/dynamicmaps.c b/postfix/src/global/dynamicmaps.c
new file mode 100644 (file)
index 0000000..b4e4176
--- /dev/null
@@ -0,0 +1,292 @@
+/*++
+/* NAME
+/*     dynamicmaps 3
+/* SUMMARY
+/*     load dictionaries dynamically
+/* SYNOPSIS
+/*     #include <dynamicmaps.h>
+/*
+/*     void dymap_init(const char *path)
+/*
+/*     ARGV *dymap_list(ARGV *map_names)
+/* DESCRIPTION
+/*     This module reads the dynamicmaps.cf file and performs
+/*     run-time loading of Postfix dictionaries. Each dynamicmaps.cf
+/*     entry specifies the name of a dictionary type, the pathname
+/*     of a shared-library object, the name of an "open" function
+/*     for access to individual dictionary entries, and optionally
+/*     the name of a "mkmap" function for bulk-mode dictionary
+/*     creation.
+/*
+/*     dymap_init() must be called at least once before any other
+/*     functions in this module.  This function reads the specified
+/*     configuration file which is in dynamicmaps.cf format, hooks
+/*     itself into the dict_open(), dict_mapames(), and mkmap_open()
+/*     functions, and may be called multiple times during a process
+/*     lifetime, but only the last-read dynamicmaps content will be
+/*     remembered.
+/*
+/*     dymap_list() appends to its argument the names of dictionary
+/*     types available in dynamicmaps.cf.
+/* SEE ALSO
+/*     load_lib(3) low-level run-time linker adapter
+/* DIAGNOSTICS
+/*     Fatal errors: memory allocation problem, dictionary or
+/*     dictionary function not available.  Panic: invalid use.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     LaMont Jones
+/*     Hewlett-Packard Company
+/*     3404 Harmony Road
+/*     Fort Collins, CO 80528, USA
+/*
+/*     Wietse Venema
+/*     IBM T.J. Watson Research
+/*     P.O. Box 704
+/*     Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <sys/stat.h>
+#include <string.h>
+
+ /*
+  * Utility library.
+  */
+#include <msg.h>
+#include <mymalloc.h>
+#include <argv.h>
+#include <dict.h>
+#include <load_lib.h>
+#include <vstring.h>
+#include <vstream.h>
+#include <vstring_vstream.h>
+#include <mvect.h>
+
+ /*
+  * Global library.
+  */
+#include <mkmap.h>
+#include <dynamicmaps.h>
+
+#ifdef USE_DYNAMIC_LIBS
+
+ /*
+  * Contents of one dynamicmaps.cf entry.
+  */
+typedef struct {
+    const char *dict_type;             /* database type name */
+    const char *soname;                        /* shared-object file name */
+    const char *open_name;             /* dict_xx_open() function name */
+    const char *mkmap_name;            /* mkmap_xx_open() function name */
+} DYMAP_INFO;
+
+static DYMAP_INFO *dymap_info;
+static DICT_OPEN_EXTEND_FN saved_dict_open_hook = 0;
+static MKMAP_OPEN_EXTEND_FN saved_mkmap_open_hook = 0;
+static DICT_MAPNAMES_EXTEND_FN saved_dict_mapnames_hook = 0;
+
+#define STREQ(x, y) (strcmp((x), (y)) == 0)
+
+/* dymap_find - find dynamicmaps.cf metadata */
+
+static DYMAP_INFO *dymap_find(const char *dict_type)
+{
+    static const char myname[] = "dymap_find";
+    DYMAP_INFO *dp;
+
+    if (!dymap_info)
+       msg_panic("%s: dlinfo==NULL", myname);
+
+    for (dp = dymap_info; dp->dict_type; dp++) {
+       if (STREQ(dp->dict_type, dict_type))
+           return dp;
+    }
+    return (0);
+}
+
+/* dymap_open_lookup - look up "dict_foo_open" function */
+
+static DICT_OPEN_FN dymap_open_lookup(const char *dict_type)
+{
+    struct stat st;
+    LIB_FN  fn[2];
+    DICT_OPEN_FN dict_open_fn;
+    DYMAP_INFO *dp;
+
+    /*
+     * Respect the hook nesting order.
+     */
+    if (saved_dict_open_hook != 0
+       && (dict_open_fn = saved_dict_open_hook(dict_type)) != 0)
+       return (dict_open_fn);
+
+    /*
+     * Allow for graceful degradation when a database is unavailable. This
+     * allows daemon processes to continue handling email with reduced
+     * functionality.
+     */
+    if ((dp = dymap_find(dict_type)) == 0
+       || stat(dp->soname, &st) < 0
+       || dp->open_name == 0)
+       return (0);
+    if (st.st_uid != 0 || (st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
+       msg_warn("%s: file must be writable only by root", dp->soname);
+       return (0);
+    }
+    fn[0].name = dp->open_name;
+    fn[0].ptr = (void **) &dict_open_fn;
+    fn[1].name = NULL;
+    load_library_symbols(dp->soname, fn, NULL);
+    return (dict_open_fn);
+}
+
+/* dymap_mkmap_lookup - look up "mkmap_foo_open" function */
+
+static MKMAP_OPEN_FN dymap_mkmap_lookup(const char *dict_type)
+{
+    struct stat st;
+    LIB_FN  fn[2];
+    MKMAP_OPEN_FN mkmap_open_fn;
+    DYMAP_INFO *dp;
+
+    /*
+     * Respect the hook nesting order.
+     */
+    if (saved_mkmap_open_hook != 0
+       && (mkmap_open_fn = saved_mkmap_open_hook(dict_type)) != 0)
+       return (mkmap_open_fn);
+
+    /*
+     * All errors are fatal. If we can't create the requetsed database, then
+     * graceful degradation is not useful.
+     */
+    dp = dymap_find(dict_type);
+    if (!dp)
+       msg_fatal("unsupported dictionary type: %s. "
+                 "Is the postfix-%s package installed?",
+                 dict_type, dict_type);
+    if (!dp->mkmap_name)
+       msg_fatal("unsupported dictionary type: %s does not support "
+                 "bulk-mode creation.", dict_type);
+    if (stat(dp->soname, &st) < 0)
+       msg_fatal("unsupported dictionary type: %s (%s not found). "
+                 "Is the postfix-%s package installed?",
+                 dict_type, dp->soname, dict_type);
+    if (st.st_uid != 0 || (st.st_mode & (S_IWGRP | S_IWOTH)) != 0)
+       msg_fatal("%s: file must be writable only by root", dp->soname);
+    fn[0].name = dp->mkmap_name;
+    fn[0].ptr = (void **) &mkmap_open_fn;
+    fn[1].name = NULL;
+    load_library_symbols(dp->soname, fn, NULL);
+    return (mkmap_open_fn);
+}
+
+/* dymap_list - enumerate dynamically-linked database type names */
+
+static ARGV *dymap_list(ARGV *map_names)
+{
+    static const char myname[] = "dymap_list";
+    DYMAP_INFO *dp;
+
+    if (!dymap_info)
+       msg_panic("%s: dlinfo==NULL", myname);
+
+    /*
+     * Respect the hook nesting order.
+     */
+    if (saved_dict_mapnames_hook != 0)
+       map_names = saved_dict_mapnames_hook(map_names);
+
+    if (map_names == 0)
+       map_names = argv_alloc(2);
+    for (dp = dymap_info; dp->dict_type; dp++) {
+       argv_add(map_names, dp->dict_type, ARGV_END);
+    }
+    return (map_names);
+}
+
+/* dymap_init - initialize dictionary type to soname etc. mapping */
+
+void    dymap_init(const char *path)
+{
+    VSTREAM *conf_fp;
+    VSTRING *buf;
+    char   *cp;
+    ARGV   *argv;
+    static MVECT vector;
+    int     nelm = 0;
+    int     linenum = 0;
+    static int hooks_done = 0;
+    struct stat st;
+
+    if (dymap_info != 0)
+       mvect_free(&vector);
+
+    dymap_info =
+       (DYMAP_INFO *) mvect_alloc(&vector, sizeof(DYMAP_INFO), 3, 0, 0);
+
+    /* Silently ignore missing dynamic maps file. */
+    if ((conf_fp = vstream_fopen(path, O_RDONLY, 0)) != 0) {
+       if (fstat(vstream_fileno(conf_fp), &st) < 0)
+           msg_fatal("%s: fstat failed; %m", path);
+       if (st.st_uid != 0 || (st.st_mode & (S_IWGRP | S_IWOTH)) != 0)
+           msg_fatal("%s: file must be writable only by root", path);
+       buf = vstring_alloc(100);
+       while (vstring_get_nonl(buf, conf_fp) != VSTREAM_EOF) {
+           cp = vstring_str(buf);
+           linenum++;
+           if (*cp == '#' || *cp == '\0')
+               continue;
+           argv = argv_split(cp, " \t");
+           if (argv->argc != 3 && argv->argc != 4) {
+               msg_fatal("%s: Expected \"dict_type .so-name open-function"
+                         " [mkmap-function]\" at line %d", path, linenum);
+           }
+           if (STREQ(argv->argv[0], "*")) {
+               msg_warn("%s: wildcard dynamic map entry no longer supported.",
+                        path);
+               continue;
+           }
+           if (argv->argv[1][0] != '/') {
+               msg_fatal("%s: .so name must begin with a \"/\" at line %d",
+                         path, linenum);
+           }
+           if (nelm >= vector.nelm) {
+               dymap_info = (DYMAP_INFO *) mvect_realloc(&vector, vector.nelm + 3);
+           }
+           dymap_info[nelm].dict_type = mystrdup(argv->argv[0]);
+           dymap_info[nelm].soname = mystrdup(argv->argv[1]);
+           dymap_info[nelm].open_name = mystrdup(argv->argv[2]);
+           if (argv->argc == 4)
+               dymap_info[nelm].mkmap_name = mystrdup(argv->argv[3]);
+           else
+               dymap_info[nelm].mkmap_name = NULL;
+           nelm++;
+           argv_free(argv);
+           if (hooks_done == 0) {
+               hooks_done = 1;
+               saved_dict_open_hook = dict_open_extend(dymap_open_lookup);
+               saved_mkmap_open_hook = mkmap_open_extend(dymap_mkmap_lookup);
+               saved_dict_mapnames_hook = dict_mapnames_extend(dymap_list);
+           }
+       }
+       vstring_free(buf);
+       vstream_fclose(conf_fp);
+    }
+    if (nelm >= vector.nelm) {
+       dymap_info = (DYMAP_INFO *) mvect_realloc(&vector, vector.nelm + 1);
+    }
+    dymap_info[nelm].dict_type = NULL;
+    dymap_info[nelm].soname = NULL;
+    dymap_info[nelm].open_name = NULL;
+    dymap_info[nelm].mkmap_name = NULL;
+}
+
+#endif
similarity index 68%
rename from postfix/src/util/dynamicmaps.h
rename to postfix/src/global/dynamicmaps.h
index 5afca96b9c01f37f4f6a6ab9926a860cd9f15dc2..d1613d4fe3683bf3597e7bb251eecb195cae3771 100644 (file)
 /* DESCRIPTION
 /* .nf
 
- /*
-  * Utility library.
-  */
-#include <argv.h>
-
  /*
   * External interface.
   */
 #ifdef USE_DYNAMIC_LIBS
 
-typedef DICT *(*dymap_open_t) (const char *, int, int);
-typedef void *(*dymap_mkmap_t) (const char *);
-
 extern void dymap_init(const char *);
-extern ARGV *dymap_list(ARGV *);
-extern dymap_open_t dymap_get_open_fn(const char *);
-extern dymap_mkmap_t dymap_get_mkmap_fn(const char *);
 
 #endif
 /* LICENSE
index 73c31170a3049e5104744fbd293bc53f7343e6a1..1531aca66e7ae382c2e28da6d15fada6aab9e855 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20140508"
+#define MAIL_RELEASE_DATE      "20140516"
 #define MAIL_VERSION_NUMBER    "2.12"
 
 #ifdef SNAPSHOT
index fa5f889b66fc23b3ab47d4785612b001ff9cee0a..e49311474231d35013fae09b44c41450bd52cac3 100644 (file)
   * acquire the lock after the DB/DBM initialization.
   */
 typedef struct MKMAP {
-    struct DICT *(*open) (const char *, int, int);     /* dict_xx_open() */
+    DICT_OPEN_FN open;                 /* dict_xx_open() */
     struct DICT *dict;                 /* dict_xx_open() result */
     void    (*after_open) (struct MKMAP *);    /* may be null */
     void    (*after_close) (struct MKMAP *);   /* may be null */
-    int     multi_writer;                      /* multi-writer safe */
+    int     multi_writer;              /* multi-writer safe */
 } MKMAP;
 
 extern MKMAP *mkmap_open(const char *, const char *, int, int);
@@ -45,6 +45,11 @@ extern MKMAP *mkmap_sdbm_open(const char *);
 extern MKMAP *mkmap_proxy_open(const char *);
 extern MKMAP *mkmap_fail_open(const char *);
 
+typedef MKMAP *(*MKMAP_OPEN_FN) (const char *);
+typedef MKMAP_OPEN_FN (*MKMAP_OPEN_EXTEND_FN) (const char *);
+extern void mkmap_open_register(const char *, MKMAP_OPEN_FN);
+extern MKMAP_OPEN_EXTEND_FN mkmap_open_extend(MKMAP_OPEN_EXTEND_FN);
+
 /* LICENSE
 /* .ad
 /* .fi
index 70c79836e78e0492383d847e21e41969b5b98f76..18eedfdb153282d912209b71000b76e1b304caa6 100644 (file)
@@ -6,6 +6,14 @@
 /* SYNOPSIS
 /*     #include <mkmap.h>
 /*
+/*     typedef struct MKMAP {
+/*         DICT_OPEN_FN open;                          /* dict_xx_open() */
+/*         DICT *dict;                                 /* dict_xx_open() result */
+/*         void    (*after_open) (struct MKMAP *);     /* may be null */
+/*         void    (*after_close) (struct MKMAP *);    /* may be null */
+/*         int     multi_writer;                       /* multi-writer safe */
+/*     } MKMAP;
+/*
 /*     MKMAP   *mkmap_open(type, path, open_flags, dict_flags)
 /*     char    *type;
 /*     char    *path;
 /*
 /*     void    mkmap_close(mkmap)
 /*     MKMAP   *mkmap;
+/*
+/*     typedef MKMAP *(*MKMAP_OPEN_FN) (const char *);
+/*     typedef MKMAP_OPEN_FN *(*MKMAP_OPEN_EXTEND_FN) (const char *);
+/*
+/*     void    mkmap_open_register(type, open_fn)
+/*     const char *type;
+/*     MKMAP_OPEN_FN open_fn;
+/*
+/*     MKMAP_OPEN_EXTEND_FN mkmap_open_extend(call_back)
+/*     MKMAP_OPEN_EXTEND_FN call_back;
 /* DESCRIPTION
 /*     This module implements support for creating Postfix databases.
 /*     It is a dict(3) wrapper that adds global locking to dict-level
@@ -29,8 +47,8 @@
 /*     appending the appropriate suffixes to the specified filename.
 /*     Before the database is updated, it is locked for exclusive
 /*     access, and signal delivery is suspended.
-/*     See dict(3) for a description of \fBopen_flags\fR and \fBdict_flags\fR.
-/*     All errors are fatal.
+/*     See dict(3) for a description of \fBopen_flags\fR and
+/*     \fBdict_flags\fR.  All errors are fatal.
 /*
 /*     mkmap_append() appends the named (key, value) pair to the
 /*     database. Update errors are fatal; duplicate keys are ignored
 /*
 /*     mkmap_close() closes the database, releases any locks,
 /*     and resumes signal delivery. All errors are fatal.
+/*
+/*     mkmap_open_register() adds support for a new database type.
+/*
+/*     mkmap_open_extend() registers a call-back function that looks
+/*     up the mkmap open() function for a database type that is not
+/*     registered, or null in case of error. The result value is the
+/*     last previously-registered call-back or null. A mkmap open()
+/*     function is cached after it is looked up through this extension
+/*     mechanism.
 /* SEE ALSO
 /*     sigdelay(3) suspend/resume signal delivery
 /* LICENSE
@@ -61,6 +88,7 @@
 /* Utility library. */
 
 #include <msg.h>
+#include <htable.h>
 #include <dict.h>
 #include <dict_db.h>
 #include <dict_cdb.h>
 #include <sigdelay.h>
 #include <mymalloc.h>
 
-#ifdef USE_DYNAMIC_LIBS
-#include <dynamicmaps.h>
-#endif
-
 /* Global library. */
 
 #include "mkmap.h"
 
  /*
   * Information about available database types. Here, we list only those map
-  * types that support "create" operations.
+  * types that support "bulk create" operations.
   * 
-  * We use a different table (in dict_open.c) when querying maps.
+  * We use a different table (in dict_open.c and mail_dict.c) when querying maps
+  * or when making incremental updates.
   */
 typedef struct {
     const char *type;
-    MKMAP  *(*before_open) (const char *);
+    MKMAP_OPEN_FN before_open;
 } MKMAP_OPEN_INFO;
 
-static const MKMAP_OPEN_INFO mkmap_types[] = {
-    DICT_TYPE_PROXY, mkmap_proxy_open,
+static const MKMAP_OPEN_INFO mkmap_open_info[] = {
 #ifdef HAS_CDB
     DICT_TYPE_CDB, mkmap_cdb_open,
 #endif
@@ -113,6 +137,54 @@ static const MKMAP_OPEN_INFO mkmap_types[] = {
     0,
 };
 
+static HTABLE *mkmap_open_hash;
+
+static MKMAP_OPEN_EXTEND_FN mkmap_open_extend_hook = 0;
+
+/* mkmap_open_init - one-off initialization */
+
+static void mkmap_open_init(void)
+{
+    const char myname[] = "mkmap_open_init";
+    const MKMAP_OPEN_INFO *mp;
+
+    if (mkmap_open_hash != 0)
+       msg_panic("%s: multiple initialization", myname);
+    mkmap_open_hash = htable_create(10);
+
+    for (mp = mkmap_open_info; mp->type; mp++)
+       htable_enter(mkmap_open_hash, mp->type, (char *) mp);
+}
+
+/* mkmap_open_register - register dictionary type */
+
+void    mkmap_open_register(const char *type, MKMAP_OPEN_FN open_fn)
+{
+    const char myname[] = "mkmap_open_register";
+    MKMAP_OPEN_INFO *mp;
+    HTABLE_INFO *ht;
+
+    if (mkmap_open_hash == 0)
+       mkmap_open_init();
+    if (htable_find(mkmap_open_hash, type))
+       msg_panic("%s: database type exists: %s", myname, type);
+    mp = (MKMAP_OPEN_INFO *) mymalloc(sizeof(*mp));
+    mp->before_open = open_fn;
+    ht = htable_enter(mkmap_open_hash, type, (char *) mp);
+    mp->type = ht->key;
+}
+
+/* mkmap_open_extend - register alternate lookup function */
+
+MKMAP_OPEN_EXTEND_FN mkmap_open_extend(MKMAP_OPEN_EXTEND_FN new_cb)
+{
+    MKMAP_OPEN_EXTEND_FN old_cb;
+
+    old_cb = mkmap_open_extend_hook;
+    mkmap_open_extend_hook = new_cb;
+    return (old_cb);
+}
+
 /* mkmap_append - append entry to map */
 
 #undef mkmap_append
@@ -164,30 +236,21 @@ MKMAP  *mkmap_open(const char *type, const char *path,
 {
     MKMAP  *mkmap;
     const MKMAP_OPEN_INFO *mp;
-
-#ifdef USE_DYNAMIC_LIBS
-    MKMAP_OPEN_INFO oi;
-
-#endif
+    MKMAP_OPEN_FN open_fn;
 
     /*
      * Find out what map type to use.
      */
-    for (mp = mkmap_types; /* void */ ; mp++) {
-       if (mp->type == 0) {
-#ifdef USE_DYNAMIC_LIBS
-           /* Either returns a handle, or raises a fatal error */
-           oi.before_open =
-               (MKMAP *(*) (const char *)) dymap_get_mkmap_fn(type);
-           oi.type = type;
-           mp = &oi;
-           break;
-#else
-           msg_fatal("unsupported map type for this operation: %s", type);
-#endif
+    if (mkmap_open_hash == 0)
+       mkmap_open_init();
+    if ((mp = (MKMAP_OPEN_INFO *) htable_find(mkmap_open_hash, type)) == 0) {
+       if (mkmap_open_extend_hook != 0 &&
+           (open_fn = mkmap_open_extend_hook(type)) != 0) {
+           mkmap_open_register(type, open_fn);
+           mp = (MKMAP_OPEN_INFO *) htable_find(mkmap_open_hash, type);
        }
-       if (strcmp(type, mp->type) == 0)
-           break;
+       if (mp == 0)
+           msg_fatal("unsupported map type for this operation: %s", type);
     }
     if (msg_verbose)
        msg_info("open %s %s", type, path);
index d63aca845a6077d7ef499749baf72562c187aabb..954fecfaf50d68a73b78aea126406fc977ec9d52 100644 (file)
@@ -1341,6 +1341,7 @@ int     main(int argc, char **argv)
 
     single_server_main(argc, argv, pipe_service,
                       MAIL_SERVER_TIME_TABLE, time_table,
+                      MAIL_SERVER_STR_TABLE, str_table,
                       MAIL_SERVER_PRE_INIT, pre_init,
                       MAIL_SERVER_POST_INIT, drop_privileges,
                       MAIL_SERVER_PRE_ACCEPT, pre_accept,
index e589503c3707c413726f093b14fdf646fdb251cf..1dec35497a06357d39a525bc1663d749ddaef13a 100644 (file)
@@ -21,16 +21,16 @@ Makefile: Makefile.in
        cat ../../conf/makedefs.out $? >$@
 
 smtp-sink: smtp-sink.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ smtp-sink.o $(LIBS) $(SYSLIBS)
+       $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ smtp-sink.o $(LIBS) $(SYSLIBS)
 
 smtp-source: smtp-source.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ smtp-source.o $(LIBS) $(SYSLIBS)
+       $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ smtp-source.o $(LIBS) $(SYSLIBS)
 
 qmqp-sink: qmqp-sink.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ qmqp-sink.o $(LIBS) $(SYSLIBS)
+       $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ qmqp-sink.o $(LIBS) $(SYSLIBS)
 
 qmqp-source: qmqp-source.o $(LIBS)
-       $(CC) $(CFLAGS) -o $@ qmqp-source.o $(LIBS) $(SYSLIBS)
+       $(CC) $(CFLAGS) $(SHLIB_RPATH) -o $@ qmqp-source.o $(LIBS) $(SYSLIBS)
 
 test:  $(TESTPROG)
 
index b1e1e84d18aa0c03e11bd714ebd2c50e9f55f445..c50a450b4228a9c62fa50647cc07f6fbc35b1796 100644 (file)
@@ -21,7 +21,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        readlline.c ring.c safe_getenv.c safe_open.c \
        sane_accept.c sane_connect.c sane_link.c sane_rename.c \
        sane_socketpair.c sane_time.c scan_dir.c set_eugid.c set_ugid.c \
-       load_lib.c dynamicmaps.c \
+       load_lib.c \
        sigdelay.c skipblanks.c sock_addr.c spawn_command.c split_at.c \
        split_nameval.c stat_as.c strcasecmp.c stream_connect.c \
        stream_listen.c stream_recv_fd.c stream_send_fd.c stream_trigger.c \
@@ -52,7 +52,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        host_port.o htable.o inet_addr_host.o inet_addr_list.o \
        inet_addr_local.o inet_connect.o inet_listen.o inet_proto.o \
        inet_trigger.o line_wrap.o lowercase.o lstat_as.o mac_expand.o \
-       load_lib.o dynamicmaps.o \
+       load_lib.o \
        mac_parse.o make_dirs.o mask_addr.o match_list.o match_ops.o msg.o \
        msg_output.o msg_syslog.o msg_vstream.o mvect.o myaddrinfo.o myflock.o \
        mymalloc.o myrand.o mystrtok.o name_code.o name_mask.o netstring.o \
@@ -91,7 +91,7 @@ HDRS  = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        mymalloc.h myrand.h name_code.h name_mask.h netstring.h nvtable.h \
        open_as.h open_lock.h percentm.h posix_signals.h readlline.h ring.h \
        safe.h safe_open.h sane_accept.h sane_connect.h sane_fsops.h \
-       load_lib.h dynamicmaps.h \
+       load_lib.h \
        sane_socketpair.h sane_time.h scan_dir.h set_eugid.h set_ugid.h \
        sigdelay.h sock_addr.h spawn_command.h split_at.h stat_as.h \
        stringops.h sys_defs.h timed_connect.h timed_wait.h trigger.h \
@@ -1454,6 +1454,10 @@ load_file.o: sys_defs.h
 load_file.o: vbuf.h
 load_file.o: vstream.h
 load_file.o: warn_stat.h
+load_lib.o: load_lib.c
+load_lib.o: load_lib.h
+load_lib.o: msg.h
+load_lib.o: sys_defs.h
 lowercase.o: lowercase.c
 lowercase.o: stringops.h
 lowercase.o: sys_defs.h
index a217603e6b5501ac886a32c5697238d05e469c8c..c705eb668b0f6aee693089dd5577e1fcaba56e68 100644 (file)
@@ -165,6 +165,9 @@ extern DICT *dict_debug(DICT *);
   * Interface for dictionary types.
   */
 extern ARGV *dict_mapnames(void);
+typedef ARGV *(*DICT_MAPNAMES_EXTEND_FN) (ARGV *);
+extern DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(DICT_MAPNAMES_EXTEND_FN);
+
 
  /*
   * High-level interface, with logical dictionary names.
@@ -184,9 +187,12 @@ extern int dict_error(const char *);
  /*
   * Low-level interface, with physical dictionary handles.
   */
+typedef DICT *(*DICT_OPEN_FN) (const char *, int, int);
+typedef DICT_OPEN_FN (*DICT_OPEN_EXTEND_FN) (const char *);
 extern DICT *dict_open(const char *, int, int);
 extern DICT *dict_open3(const char *, const char *, int, int);
-extern void dict_open_register(const char *, DICT *(*) (const char *, int, int));
+extern void dict_open_register(const char *, DICT_OPEN_FN);
+extern DICT_OPEN_EXTEND_FN dict_open_extend(DICT_OPEN_EXTEND_FN);
 
 #define dict_get(dp, key)      ((const char *) (dp)->lookup((dp), (key)))
 #define dict_put(dp, key, val) (dp)->update((dp), (key), (val))
index 93ee48098fa4025db936a167abee13eb35d5a306..4a09939a55b582d4d8d90ba9793ac39c92d8dab8 100644 (file)
@@ -89,7 +89,7 @@
 #define DONT_CLOBBER                   DB_NOOVERWRITE
 #endif
 
-#if (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6)
+#if (DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR <= 6)
 #define DICT_DB_CURSOR(db, curs)       (db)->cursor((db), NULL, (curs))
 #else
 #define DICT_DB_CURSOR(db, curs)       (db)->cursor((db), NULL, (curs), 0)
@@ -693,7 +693,8 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
        msg_fatal("set DB cache size %d: %m", dict_db_cache_size);
     if (type == DB_HASH && db->set_h_nelem(db, DICT_DB_NELM) != 0)
        msg_fatal("set DB hash element count %d: %m", DICT_DB_NELM);
-#if DB_VERSION_MAJOR == 5 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0)
+#if DB_VERSION_MAJOR == 6 || DB_VERSION_MAJOR == 5 || \
+       (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR > 0)
     if ((errno = db->open(db, 0, db_path, 0, type, db_flags, 0644)) != 0)
        FREE_RETURN(dict_surrogate(class, path, open_flags, dict_flags,
                                   "open database %s: %m", db_path));
index 3dfff403c01628acc7d94ea4d91f5bceb63f3e26..cb9f4b75cb1f7e2206249bc5e9f6a1f09eedc6cf 100644 (file)
 /*     void    dict_close(dict)
 /*     DICT    *dict;
 /*
+/*     typedef DICT *(*DICT_OPEN_FN) (const char *, int, int);
+/*
 /*     dict_open_register(type, open)
-/*     char    *type;
-/*     DICT    *(*open) (const char *, int, int);
+/*     const char *type;
+/*     DICT_OPEN_FN open;
+/*
+/*     typedef DICT_OPEN_FN (*DICT_OPEN_EXTEND_FN)(const char *type);
+/*
+/*     DICT_OPEN_EXTEND_FN dict_open_extend(call_back)
+/*     DICT_OPEN_EXTEND_FN call_back;
 /*
 /*     ARGV    *dict_mapnames()
 /*
+/*     typedef ARGV *(*DICT_MAPNAMES_EXTEND_FN)(ARGV *names);
+/*
+/*     DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(call_back)
+/*     DICT_MAPNAMES_EXTEND_FN call_back;
+/*
 /*     int     dict_isjmp(dict)
 /*     DICT    *dict;
 /*
 /*
 /*     dict_open_register() adds support for a new dictionary type.
 /*
+/*     dict_open_extend() registers a call-back function that looks
+/*     up the dictionary open() function for a type that is not
+/*     registered, or null in case of error. The result value is
+/*     the last previously-registered call-back or null.
+/*
 /*     dict_mapnames() returns a sorted list with the names of all available
 /*     dictionary types.
 /*
+/*     dict_mapnames_extend() registers a call-back function that
+/*     enumerates additional dictionary type names. The result
+/*     will be sorted by dict_mapnames().  The result value
+/*     is the last previously-registered call-back or null.
+/*
 /*     dict_setjmp() saves processing context and makes that context
 /*     available for use with dict_longjmp().  Normally, dict_setjmp()
 /*     returns zero.  A non-zero result means that dict_setjmp()
 #include <split_at.h>
 #include <htable.h>
 #include <myflock.h>
-#include <dynamicmaps.h>
 
  /*
   * lookup table for available map types.
   */
 typedef struct {
     char   *type;
-    struct DICT *(*open) (const char *, int, int);
+    DICT_OPEN_FN open;
 } DICT_OPEN_INFO;
 
 static const DICT_OPEN_INFO dict_open_info[] = {
@@ -336,6 +357,12 @@ static const DICT_OPEN_INFO dict_open_info[] = {
 
 static HTABLE *dict_open_hash;
 
+ /*
+  * Extension hooks.
+  */
+static DICT_OPEN_EXTEND_FN dict_open_extend_hook;
+static DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend_hook;
+
 /* dict_open_init - one-off initialization */
 
 static void dict_open_init(void)
@@ -376,6 +403,7 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
 {
     const char *myname = "dict_open";
     DICT_OPEN_INFO *dp;
+    DICT_OPEN_FN open_fn;
     DICT   *dict;
 
     if (*dict_type == 0 || *dict_name == 0)
@@ -384,18 +412,14 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
     if (dict_open_hash == 0)
        dict_open_init();
     if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0) {
-#ifdef USE_DYNAMIC_LIBS
-       dymap_open_t open_fn;
-
-       if ((open_fn = dymap_get_open_fn(dict_type)) == 0)
+       if (dict_open_extend_hook != 0
+           && (open_fn = dict_open_extend_hook(dict_type)) != 0) {
+           dict_open_register(dict_type, open_fn);
+           dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type);
+       }
+       if (dp == 0)
            return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
                             "unsupported dictionary type: %s", dict_type));
-       dict_open_register(dict_type, open_fn);
-       dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type);
-#else
-       return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
-                            "unsupported dictionary type: %s", dict_type));
-#endif
     }
     if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
        return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
@@ -422,20 +446,31 @@ DICT   *dict_open3(const char *dict_type, const char *dict_name,
 
 /* dict_open_register - register dictionary type */
 
-void    dict_open_register(const char *type,
-                                  DICT *(*open) (const char *, int, int))
+void    dict_open_register(const char *type, DICT_OPEN_FN open)
 {
     const char *myname = "dict_open_register";
     DICT_OPEN_INFO *dp;
+    HTABLE_INFO *ht;
 
     if (dict_open_hash == 0)
        dict_open_init();
     if (htable_find(dict_open_hash, type))
        msg_panic("%s: dictionary type exists: %s", myname, type);
     dp = (DICT_OPEN_INFO *) mymalloc(sizeof(*dp));
-    dp->type = mystrdup(type);
     dp->open = open;
-    htable_enter(dict_open_hash, dp->type, (char *) dp);
+    ht = htable_enter(dict_open_hash, type, (char *) dp);
+    dp->type = ht->key;
+}
+
+/* dict_open_extend - register alternate dictionary search routine */
+
+DICT_OPEN_EXTEND_FN dict_open_extend(DICT_OPEN_EXTEND_FN new_cb)
+{
+    DICT_OPEN_EXTEND_FN old_cb;
+
+    old_cb = dict_open_extend_hook;
+    dict_open_extend_hook = new_cb;
+    return (old_cb);
 }
 
 /* dict_sort_alpha_cpp - qsort() callback */
@@ -461,9 +496,8 @@ ARGV   *dict_mapnames()
        dp = (DICT_OPEN_INFO *) ht[0]->value;
        argv_add(mapnames, dp->type, ARGV_END);
     }
-#ifdef USE_DYNAMIC_LIBS
-    dymap_list(mapnames);
-#endif
+    if (dict_mapnames_extend_hook != 0)
+       (void) dict_mapnames_extend_hook(mapnames);
     qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]),
          dict_sort_alpha_cpp);
     myfree((char *) ht_info);
@@ -471,6 +505,17 @@ ARGV   *dict_mapnames()
     return mapnames;
 }
 
+/* dict_mapnames_extend - register alternate dictionary type list routine */
+
+DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend(DICT_MAPNAMES_EXTEND_FN new_cb)
+{
+    DICT_MAPNAMES_EXTEND_FN old_cb;
+
+    old_cb = dict_mapnames_extend_hook;
+    dict_mapnames_extend_hook = new_cb;
+    return (old_cb);
+}
+
 #ifdef TEST
 
  /*
diff --git a/postfix/src/util/dynamicmaps.c b/postfix/src/util/dynamicmaps.c
deleted file mode 100644 (file)
index 5221b3c..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*++
-/* NAME
-/*     dynamicmaps 3
-/* SUMMARY
-/*     load dictionaries dynamically
-/* SYNOPSIS
-/*     #include <dynamicmaps.h>
-/*
-/*     typedef void *(*dymap_mkmap_t) (const char *)
-/*     typedef DICT *(*dymap_open_t) (const char *, int, int)
-/*
-/*     void dymap_init(const char *path)
-/*
-/*     ARGV *dymap_list(ARGV *map_names)
-/*
-/*     dymap_open_t dymap_get_open_fn(const char *dict_type)
-/*
-/*     dymap_mkmap_t dymap_get_mkmap_fn(const char *dict_type)
-/* DESCRIPTION
-/*     This module reads the dynamicmaps.cf file and performs
-/*     run-time loading of Postfix dictionaries. Each dynamicmaps.cf
-/*     entry specifies the name of a dictionary type, the pathname
-/*     of a shared-library object, the name of an "open" function
-/*     for access to individual dictionary entries, and optionally
-/*     the name of a "mkmap" function for bulk-mode dictionary
-/*     creation.
-/*
-/*     dymap_init() must be called at least once before any other
-/*     functions in this module.  This function reads the specified
-/*     configuration file which is in dynamicmaps.cf format, and
-/*     may be called multiple times during a process lifetime.
-/*
-/*     dymap_list() appends to its argument the names of dictionary
-/*     types available in dynamicmaps.cf.
-/*
-/*     dymap_get_open_fn() loads the specified dictionary and
-/*     returns a function pointer to its "open" function.
-/*
-/*     dymap_get_mkmap_fn() loads the specified dictionary and
-/*     returns a function pointer to its "mkmap" function.
-/* SEE ALSO
-/*     load_lib(3) low-level run-time linker adapter
-/* DIAGNOSTICS
-/*     Fatal errors: memory allocation problem, dictionary or
-/*     dictionary function not available.  Panic: invalid use.
-/* LICENSE
-/* .ad
-/* .fi
-/*     The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/*     LaMont Jones
-/*     Hewlett-Packard Company
-/*     3404 Harmony Road
-/*     Fort Collins, CO 80528, USA
-/*
-/*     Wietse Venema
-/*     IBM T.J. Watson Research
-/*     P.O. Box 704
-/*     Yorktown Heights, NY 10598, USA
-/*--*/
-
- /*
-  * System library.
-  */
-#include <sys_defs.h>
-#include <sys/stat.h>
-#include <string.h>
-
- /*
-  * Utility library.
-  */
-#include <msg.h>
-#include <mymalloc.h>
-#include <argv.h>
-#include <dict.h>
-#include <load_lib.h>
-#include <dynamicmaps.h>
-#include <load_lib.h>
-#include <vstring.h>
-#include <vstream.h>
-#include <vstring_vstream.h>
-#include <mvect.h>
-
-#ifdef USE_DYNAMIC_LIBS
-
- /*
-  * Contents of one dynamicmaps.cf entry.
-  */
-typedef struct {
-    const char *dict_type;
-    const char *soname;
-    const char *open_name;
-    const char *mkmap_name;
-} DICT_DL_INFO;
-
-static DICT_DL_INFO *dict_dlinfo;
-
-#define STREQ(x, y) (strcmp((x), (y)) == 0)
-
-/* dymap_init - initialize dictionary type to soname etc. mapping */
-
-void    dymap_init(const char *path)
-{
-    VSTREAM *conf_fp;
-    VSTRING *buf;
-    char   *cp;
-    ARGV   *argv;
-    static MVECT vector;
-    int     nelm = 0;
-    int     linenum = 0;
-
-    if (dict_dlinfo != 0)
-       mvect_free(&vector);
-
-    dict_dlinfo =
-       (DICT_DL_INFO *) mvect_alloc(&vector, sizeof(DICT_DL_INFO), 3, 0, 0);
-
-    /* Silently ignore missing dynamic maps file. */
-    if ((conf_fp = vstream_fopen(path, O_RDONLY, 0)) != 0) {
-       buf = vstring_alloc(100);
-       while (vstring_get_nonl(buf, conf_fp) != VSTREAM_EOF) {
-           cp = vstring_str(buf);
-           linenum++;
-           if (*cp == '#' || *cp == '\0')
-               continue;
-           argv = argv_split(cp, " \t");
-           if (argv->argc != 3 && argv->argc != 4) {
-               msg_fatal("%s: Expected \"dict_type .so-name open-function"
-                         " [mkmap-function]\" at line %d", path, linenum);
-           }
-           if (STREQ(argv->argv[0], "*")) {
-               msg_warn("%s: wildcard dynamic map entry no longer supported.",
-                        path);
-               continue;
-           }
-           if (argv->argv[1][0] != '/') {
-               msg_fatal("%s: .so name must begin with a \"/\" at line %d",
-                         path, linenum);
-           }
-           if (nelm >= vector.nelm) {
-               dict_dlinfo = (DICT_DL_INFO *) mvect_realloc(&vector, vector.nelm + 3);
-           }
-           dict_dlinfo[nelm].dict_type = mystrdup(argv->argv[0]);
-           dict_dlinfo[nelm].soname = mystrdup(argv->argv[1]);
-           dict_dlinfo[nelm].open_name = mystrdup(argv->argv[2]);
-           if (argv->argc == 4)
-               dict_dlinfo[nelm].mkmap_name = mystrdup(argv->argv[3]);
-           else
-               dict_dlinfo[nelm].mkmap_name = NULL;
-           nelm++;
-           argv_free(argv);
-       }
-       vstring_free(buf);
-       vstream_fclose(conf_fp);
-    }
-    if (nelm >= vector.nelm) {
-       dict_dlinfo = (DICT_DL_INFO *) mvect_realloc(&vector, vector.nelm + 1);
-    }
-    dict_dlinfo[nelm].dict_type = NULL;
-    dict_dlinfo[nelm].soname = NULL;
-    dict_dlinfo[nelm].open_name = NULL;
-    dict_dlinfo[nelm].mkmap_name = NULL;
-}
-
-/* dymap_list - enumerate dynamically-linked database type names */
-
-ARGV   *dymap_list(ARGV *map_names)
-{
-    static const char myname[] = "dymap_list";
-    DICT_DL_INFO *dl;
-
-    if (!dict_dlinfo)
-       msg_panic("%s: dlinfo==NULL", myname);
-    if (map_names == 0)
-       map_names = argv_alloc(2);
-    for (dl = dict_dlinfo; dl->dict_type; dl++) {
-       argv_add(map_names, dl->dict_type, ARGV_END);
-    }
-    return (map_names);
-}
-
-/* dymap_find - find dynamically-linked database metadata */
-
-static DICT_DL_INFO *dymap_find(const char *dict_type)
-{
-    static const char myname[] = "dymap_find";
-    DICT_DL_INFO *dp;
-
-    if (!dict_dlinfo)
-       msg_panic("%s: dlinfo==NULL", myname);
-
-    for (dp = dict_dlinfo; dp->dict_type; dp++) {
-       if (STREQ(dp->dict_type, dict_type))
-           return dp;
-    }
-    return (0);
-}
-
-/* dymap_get_open_fn - look up "dict_foo_open" function */
-
-dymap_open_t dymap_get_open_fn(const char *dict_type)
-{
-    struct stat st;
-    LIB_FN  fn[2];
-    dymap_open_t open_fn;
-    DICT_DL_INFO *dl;
-
-    if ((dl = dymap_find(dict_type)) == 0
-       || stat(dl->soname, &st) < 0
-       || dl->open_name == 0)
-       return (0);
-    fn[0].name = dl->open_name;
-    fn[0].ptr = (void **) &open_fn;
-    fn[1].name = NULL;
-    load_library_symbols(dl->soname, fn, NULL);
-    return (open_fn);
-}
-
-/* dymap_get_mkmap_fn - look up "mkmap_foo_open" function */
-
-dymap_mkmap_t dymap_get_mkmap_fn(const char *dict_type)
-{
-    struct stat st;
-    LIB_FN  fn[2];
-    dymap_mkmap_t mkmap_fn;
-    DICT_DL_INFO *dl;
-
-    dl = dymap_find(dict_type);
-    if (!dl)
-       msg_fatal("unsupported dictionary type: %s. "
-                 "Is the postfix-%s package installed?",
-                 dict_type, dict_type);
-    if (stat(dl->soname, &st) < 0) {
-       msg_fatal("unsupported dictionary type: %s (%s not found). "
-                 "Is the postfix-%s package installed?",
-                 dict_type, dl->soname, dict_type);
-    }
-    if (!dl->mkmap_name)
-       msg_fatal("unsupported dictionary type: %s does not support "
-                 "bulk-mode creation.", dict_type);
-    fn[0].name = dl->mkmap_name;
-    fn[0].ptr = (void **) &mkmap_fn;
-    fn[1].name = NULL;
-    load_library_symbols(dl->soname, fn, NULL);
-    return (mkmap_fn);
-}
-
-#endif