Cleanup: unit tests. File: cleanup/cleanup_milter.c.
- Cleamup: disable hash-table seed in unit tests. Many
+ Cleanup: disable hash-table seed in unit tests. Many
Makefiles, some unit test 'reference' files.
Bugfix (documented but not implemented since Postfix 2.2):
mantools/check-spell-install-proto-text.
Cleanup: for consistent parameter naming (tlsproxy_client_xxx
- correspnds to smtp_tls_xxx), renamed tlsproxy_client_level
+ corresponds to smtp_tls_xxx), renamed tlsproxy_client_level
to tlsproxy_client_security_level, and tlsproxy_client_policy
to tlsproxy_client_policy_maps, with backwards-compatible
defaults and updated documentation. Problem reported by
20220128
- Clenaup: standardize on FNV hash, after having verified
+ Cleanup: standardize on FNV hash, after having verified
that collisions will change with the hash seed value, and
that the collision rate is low. Files: util/htable.c,
util/hash_fnv.[hc].
20220421
Bugfix (introduced: Postfix 3.7): reverted an overly complex
- change in the postscreen SMTP engine from 20211023, that
- was segfaulting on malformed input, where the Postfix 3.6
- implementation worked properly. The purpose of the change
- was to prevent complaints about "malformed UTF8" from Postfix
- lookup tables. Replaced the change with a trivial guard.
- File: postscreen/postscreen_smtpd.c.
+ change in the postscreen SMTP engine from 20211023, and
+ replaced it with a much simpler change. The bad change was
+ segfaulting on some systems after receiving malformed input
+ (for example, TLS "hello"). File: postscreen/postscreen_smtpd.c.
+
+ Under conditions described below, the postscreen program
+ attempted to read through an uninitialized 'const' pointer.
+ The pointer value depended on the compiler type and compiler
+ options, but crucially, it did not depend on network inputs.
+
+ The conditions were that SMTPUTF8 support was enabled (the
+ default), and that postscreen received non-UTF8 input, for
+ example, a TLS or RDP handshake request.
+
+ Depending on compiler details, the result of the read
+ operation could be uninteresting, a combined memory leak
+ and file handle leak, or a segmentation violation (signal
+ 11).
+
+ The segmentation violation result was reported by Michael
+ Grimm who used a FreeBSD 13.1 early version. The result was
+ "uninteresting" with FreeBSD 13.0. Both FreeBSD systems use
+ Clang instead of GCC. The result was also "uninteresting"
+ on Linux-based systems that use GCC, or on a few older
+ systems that use GCC.
+
+20220427
+
+ Cleanup: incorrect error message after postscreen received
+ a STARTTLS command with too many arguments. File:
+ postscreen/postscreen_smtpd.c.
+
+20220429
+
+ Noise: shut up a useless warning. File: cleanup_map1n.c.
+
+ Documentation: IPv6 support, by Pau Amma. Files: proto/INSTALL,
+ proto/IPV6_README.html.
+
+20220501
+
+ Cleanup: merged the infrastructure that "knows" which tables
+ are created with "postmap" or "postalias", with infrastructure
+ that has other information about lookup tables. The old design
+ pre-dated dynamically-loaded table drivers, and was difficult
+ to maintain.
+
+ The following files were moved from the "global" directory to
+ the "util" directory: src/util/mkmap.h, src/util/mkmap_cdb.c,
+ src/util/mkmap_db.c, src/util/mkmap_dbm.c, src/util/mkmap_fail.c,
+ src/util/mkmap_lmdb.c, src/util/mkmap_open.c,
+ src/util/mkmap_sdbm.c.
+
+ The corresponding postfix-xxx.so shared objects are now created
+ by util/Makefile instead of global/Makefile. There is no change
+ in how these files are installed or deployed.
+
+ Other files affected by this change: src/util/dict_open.c,
+ src/global/dynamicmaps.c, src/global/mail_version.h,
+ src/global/header_body_checks.h, src/global/maps.c,
+ src/global/dict_proxy.h, src/util/dict.c, src/util/dict_dbm.h,
+ src/util/dict_fail.h, src/util/dict_db.h, src/util/dict_lmdb.h,
+ src/util/dict_cdb.h, src/util/dict_sdbm.h, src/util/dict.h,
+ src/global/mail_dict.c, src/postalias/postalias.c,
+ src/postmap/postmap.c.
+
+ Portability: variable declaration after code. File:
+ global/compat_level.c.
+
+20220504
+
+ Documentation: dymap_init() description. File:
+ global/dynamicmaps.c.
+
+20220506
+
+ Added an argv_uniq() function to deduplicate same-value
+ adjacent array elements. Added a ton of tests to validate
+ the argv implementation. File: util/argv.c.
+
+ Cleanup: the dict_mapnames() function (used in "postconf
+ -m") now deduplicates dictionary type names. File:
+ util/dict_open.c.
+
+20220507
+
+ Documentation: inverted the paragraph about "known" addresses,
+ in the descriptions of smtpd_reject_unlisted_sender and
+ smtpd_reject_unlisted_recipient. File: proto/postconf.proto.
+
+ Documentation: added the HISTORY file to the pre-release-checks.
+ Files: mantools/check-double-history, mantools/check-spell-history,
+ proto/stop.double-history, proto/stop.spell-history.
+
+ Documentation: added POSTLOG_SERVICE and POSTLOG_HOSTNAME
+ to the import_environment description. File: proto/postconf.proto.
|| |Do not build with IPv6 support. By default, |
|| |IPv6 support is compiled in on platforms that|
|| |are known to have IPv6 support. Note: this |
-||-DNO_IPV6 |directive is for debugging And testing only. |
+||-DNO_IPV6 |directive is for debugging and testing only. |
|| |It is not guaranteed to work on all |
|| |platforms. If you don't want IPv6 support, |
|| |set "inet_protocols = ipv4" in main.cf. |
# Some checks require a bin/postconf executable.
pre-release-checks: typo-check missing-proxy-read-maps-check \
- postlink-check postfix-files-check
+ postlink-check postfix-files-check check-spell-history \
+ check-double-history
postfix-files-check:
mantools/check-postfix-files | diff /dev/null -
double-proto-html:
mantools/check-double-proto-html | diff /dev/null -
+check-spell-history:
+ mantools/check-spell-history | diff /dev/null -
+
+check-double-history:
+ mantools/check-double-history | diff /dev/null -
+
# The build-time shlib_directory setting must take precedence over
# the installed main.cf settings, otherwise we can't update an
# installed system from dynamicmaps=yes<->dynamicmaps=no or from
|| |Do not build with IPv6 support. By default, |
|| |IPv6 support is compiled in on platforms that|
|| |are known to have IPv6 support. Note: this |
-||-DNO_IPV6 |directive is for debugging And testing only. |
+||-DNO_IPV6 |directive is for debugging and testing only. |
|| |It is not guaranteed to work on all |
|| |platforms. If you don't want IPv6 support, |
|| |set "inet_protocols = ipv4" in main.cf. |
On other platforms Postfix will simply use IPv4 as it has always done.
-See below for tips how to port Postfix IPv6 support to other environments.
+See "IPv6 Support for unsupported platforms" for tips to port Postfix IPv6
+support to other environments.
C\bCo\bon\bnf\bfi\big\bgu\bur\bra\bat\bti\bio\bon\bn
Note 2: on older Linux and Solaris systems, the setting "inet_protocols =
ipv6" will not prevent Postfix from accepting IPv4 connections.
+ For an unsupported test option to build Postfix without IPv6 support, see
+ the NO_IPV6 option in the INSTALL document.
+
* The other new parameter is smtp_bind_address6. This sets the local
interface address for outgoing IPv6 SMTP connections, just like the
smtp_bind_address parameter does for IPv4:
more recent Eclipse Public License 2.0. Recipients can choose to take
the software under the license of their choice. Those who are more
comfortable with the IPL can continue with that license.
+
+Incompatible changes with snapshot 20220507
+===========================================
+
+Most global/mkmap*.[hc] files have moved to the util directory;
+only global/mkmap_proxy.* remains. The old file organization was
+designed before support for dynamically-loadable databases was
+added, and the code suffered from complexity.
Scan Postfix code with github.com/googleprojectzero/weggli
(depends on "rust").
+ Enforce var_line_limit in util/attr_scan*c.
+
Can tests use LD_PRELOAD to inject fake modules such as
fake_dns(3), fake_msg(3), fake_myaddrinfo(3) and so on?
One limitation is that functions etc. in a preloaded object
always take precedence, even in code that is not being
tested.
- '%l' support. ef7c661c-d86a-2366-6a73-ec8d51d75012@dev.snart.me
+ '%l' support, similar to %D in the Dovecot LDAP driver.
+ Subject: Feature request: '%l' expansion for ldap_table,
+ Date: Tue, 5 Apr 2022. Message-ID:
+ <ef7c661c-d86a-2366-6a73-ec8d51d75012@dev.snart.me>
WARN_IF_REJECT like prefix that disables the error counter increment.
<tr> <td> </td> <td> -DNO_IPV6 </td> <td> Do not build with IPv6
support. By default, IPv6 support is compiled in on platforms that
are known to have IPv6 support. Note: this directive is for debugging
-And testing only. It is not guaranteed to work on all platforms.
+and testing only. It is not guaranteed to work on all platforms.
If you don't want IPv6 support, set "<a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv4" in
<a href="postconf.5.html">main.cf</a>.
</td> </tr>
<p> On other platforms Postfix will simply use IPv4 as it has always
done. </p>
-<p> See <a href="#porting">below</a> for tips how to port Postfix
-IPv6 support to other environments. </p>
+<p> See "<a href="#porting">IPv6 Support for unsupported platforms</a>"
+for tips to port Postfix IPv6 support to other environments. </p>
<h2><a name="configuration">Configuration</a></h2>
"<a href="postconf.5.html#inet_protocols">inet_protocols</a> = ipv6" will not prevent Postfix from
accepting IPv4 connections. </p>
+<p> For an unsupported test option to build Postfix without IPv6
+support, see the NO_IPV6 option in the <a href="INSTALL.html">INSTALL</a> document. </p>
+
<li> <p> The other new parameter is <a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a>.
This sets the local interface address for outgoing IPv6 SMTP
connections, just like the <a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> parameter
<dd>Needed to make "<b>postfix -c</b>" work. </dd>
+<dt><b>POSTLOG_SERVICE</b></dt>
+
+<dd>Needed to make "<b><a href="postconf.5.html#maillog_file">maillog_file</a></b>" work during daemon
+process initialization. </dd>
+
+<dt><b>POSTLOG_HOSTNAME</b></dt>
+
+<dd>Needed to make "<b><a href="postconf.5.html#maillog_file">maillog_file</a></b>" work during daemon
+process initialization. </dd>
+
</dl>
<p> Specify a list of names and/or name=value pairs, separated by
from filling up with undeliverable MAILER-DAEMON messages.
</p>
-<p> An address is always considered "known" when it matches a
-<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping.
+<p> An address is considered "unknown" when it does not match a
+<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping, and one of the following
+conditions holds: </p>
<ul>
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses. </p>
-<p> An address is always considered "known" when it matches a
-<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping.
+<p> An address is considered "unknown" when it does not match a
+<a href="virtual.5.html">virtual(5)</a> alias or a <a href="canonical.5.html">canonical(5)</a> mapping, and one of the following
+conditions holds: </p>
<ul>
.IP "\fBMAIL_CONFIG\fR"
Needed to make "\fBpostfix \-c\fR" work.
.br
+.IP "\fBPOSTLOG_SERVICE\fR"
+Needed to make "\fBmaillog_file\fR" work during daemon
+process initialization.
+.br
+.IP "\fBPOSTLOG_HOSTNAME\fR"
+Needed to make "\fBmaillog_file\fR" work during daemon
+process initialization.
+.br
.br
.PP
Specify a list of names and/or name=value pairs, separated by
access restriction is specified. This prevents the Postfix queue
from filling up with undeliverable MAILER\-DAEMON messages.
.PP
-An address is always considered "known" when it matches a
-\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping.
+An address is considered "unknown" when it does not match a
+\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping, and one of the following
+conditions holds:
.IP \(bu
The recipient domain matches $mydestination, $inet_interfaces
or $proxy_interfaces, but the recipient is not listed in
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses.
.PP
-An address is always considered "known" when it matches a
-\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping.
+An address is considered "unknown" when it does not match a
+\fBvirtual\fR(5) alias or a \fBcanonical\fR(5) mapping, and one of the following
+conditions holds:
.IP \(bu
The sender domain matches $mydestination, $inet_interfaces or
$proxy_interfaces, but the sender is not listed in
--- /dev/null
+#!/bin/sh
+
+# Finds double words the HISTORY file, starting with 2022.
+
+LANG=C; export LANG
+
+sed '1,/^2022/d' HISTORY | mantools/find-double | fgrep -vxf proto/stop.double-history
--- /dev/null
+#!/bin/sh
+
+# Spellchecks text in the HISTORY file, starting with 2022.
+
+LANG=C; export LANG
+
+sed '1,/^2022/d' HISTORY | spell | fgrep -vxf proto/stop | \
+ fgrep -vxf proto/stop.spell-cc | \
+ fgrep -vxf proto/stop.spell-history
<tr> <td> </td> <td> -DNO_IPV6 </td> <td> Do not build with IPv6
support. By default, IPv6 support is compiled in on platforms that
are known to have IPv6 support. Note: this directive is for debugging
-And testing only. It is not guaranteed to work on all platforms.
+and testing only. It is not guaranteed to work on all platforms.
If you don't want IPv6 support, set "inet_protocols = ipv4" in
main.cf.
</td> </tr>
<p> On other platforms Postfix will simply use IPv4 as it has always
done. </p>
-<p> See <a href="#porting">below</a> for tips how to port Postfix
-IPv6 support to other environments. </p>
+<p> See "<a href="#porting">IPv6 Support for unsupported platforms</a>"
+for tips to port Postfix IPv6 support to other environments. </p>
<h2><a name="configuration">Configuration</a></h2>
"inet_protocols = ipv6" will not prevent Postfix from
accepting IPv4 connections. </p>
+<p> For an unsupported test option to build Postfix without IPv6
+support, see the NO_IPV6 option in the INSTALL document. </p>
+
<li> <p> The other new parameter is smtp_bind_address6.
This sets the local interface address for outgoing IPv6 SMTP
connections, just like the smtp_bind_address parameter
<dd>Needed to make "<b>postfix -c</b>" work. </dd>
+<dt><b>POSTLOG_SERVICE</b></dt>
+
+<dd>Needed to make "<b>maillog_file</b>" work during daemon
+process initialization. </dd>
+
+<dt><b>POSTLOG_HOSTNAME</b></dt>
+
+<dd>Needed to make "<b>maillog_file</b>" work during daemon
+process initialization. </dd>
+
</dl>
<p> Specify a list of names and/or name=value pairs, separated by
from filling up with undeliverable MAILER-DAEMON messages.
</p>
-<p> An address is always considered "known" when it matches a
-virtual(5) alias or a canonical(5) mapping.
+<p> An address is considered "unknown" when it does not match a
+virtual(5) alias or a canonical(5) mapping, and one of the following
+conditions holds: </p>
<ul>
access restriction is specified. This can slow down an explosion
of forged mail from worms or viruses. </p>
-<p> An address is always considered "known" when it matches a
-virtual(5) alias or a canonical(5) mapping.
+<p> An address is considered "unknown" when it does not match a
+virtual(5) alias or a canonical(5) mapping, and one of the following
+conditions holds: </p>
<ul>
int compar DNS_RR DNS_RR
USE_FNV_32BIT USE_FNV_32BIT
void void cleanup_milter_receive state count
+ struct DICT open const char int int dict_xx_open
--- /dev/null
+ message from the postqueue command File postqueue postqueue c
+ or kernel bug emits a weird error File postqueue postqueue c
+ Dukhovni File auxiliary collate collate pl
+ sanitization File showq showq c
+ with setgid permissions File postlogd postlogd c
+ cleanup server enters the chroot jail Files cleanup cleanup h
+ global maps c global maps h smtp smtp c
+ cleanup cleanup h cleanup cleanup_init c
+ src global mail_dict c src postalias postalias c
+ src postmap postmap c
Noll
deinit
reinit
+COMPAR
+deduplicate
--- /dev/null
+AppArmor
+Bugfix
+Degenkolb
+Dybdal
+Jaroslav
+Kimura
+Kitterman
+Klanderman
+Pelletier
+RDP
+Raf
+Skarvada
+Velasco
+WISHLIST
+Yasuhiro
+deduplicates
+hmtl
+libs
+segfaulting
+srctoman
+systemd
* pointer.
*/
#define UPDATE(ptr,new) do { \
- if (ptr) myfree(ptr); ptr = mystrdup(new); \
+ if (ptr) { myfree(ptr); } ptr = mystrdup(new); \
} while (0)
#define STR vstring_str
#define RETURN(x) do { \
mail_params.c mail_pathname.c mail_queue.c mail_run.c \
mail_scan_dir.c mail_stream.c mail_task.c mail_trigger.c maps.c \
mark_corrupt.c match_parent_style.c mbox_conf.c mbox_open.c \
- mime_state.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c mkmap_lmdb.c mkmap_open.c \
- mkmap_sdbm.c msg_stats_print.c msg_stats_scan.c mynetworks.c \
+ mime_state.c msg_stats_print.c msg_stats_scan.c mynetworks.c \
mypwd.c namadr_list.c off_cvt.c opened.c own_inet_addr.c \
pipe_command.c post_mail.c quote_821_local.c quote_822_local.c \
rcpt_buf.c rcpt_print.c rec_attr_map.c rec_streamlf.c rec_type.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 dynamicmaps.c uxtext.c \
+ haproxy_srvr.c dsn_filter.c dynamicmaps.c uxtext.c \
smtputf8.c mail_conf_over.c mail_parm_split.c midna_adomain.c \
mail_addr_form.c quote_flags.c maillog_client.c \
normalize_mailhost_addr.c map_search.c reject_deliver_request.c \
mail_params.o mail_pathname.o mail_queue.o mail_run.o \
mail_scan_dir.o mail_stream.o mail_task.o mail_trigger.o maps.o \
mark_corrupt.o match_parent_style.o mbox_conf.o mbox_open.o \
- mime_state.o mkmap_db.o mkmap_dbm.o mkmap_open.o \
- msg_stats_print.o msg_stats_scan.o mynetworks.o \
+ mime_state.o msg_stats_print.o msg_stats_scan.o mynetworks.o \
mypwd.o namadr_list.o off_cvt.o opened.o own_inet_addr.o \
pipe_command.o post_mail.o quote_821_local.o quote_822_local.o \
rcpt_buf.o rcpt_print.o rec_attr_map.o rec_streamlf.o rec_type.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 dynamicmaps.o uxtext.o \
+ haproxy_srvr.o dsn_filter.o dynamicmaps.o uxtext.o \
smtputf8.o attr_override.o mail_parm_split.o midna_adomain.o \
$(NON_PLUGIN_MAP_OBJ) mail_addr_form.o quote_flags.o maillog_client.o \
normalize_mailhost_addr.o map_search.o reject_deliver_request.o \
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these maps, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros.
-MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.o mkmap_cdb.o \
- mkmap_lmdb.o mkmap_sdbm.o
+MAP_OBJ = dict_ldap.o dict_mysql.o dict_pgsql.o dict_sqlite.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 \
mail_open_ok.h mail_params.h mail_proto.h mail_queue.h mail_run.h \
mail_scan_dir.h mail_stream.h mail_task.h mail_version.h maps.h \
mark_corrupt.h match_parent_style.h mbox_conf.h mbox_open.h \
- mime_state.h mkmap.h msg_stats.h mynetworks.h mypwd.h namadr_list.h \
+ mime_state.h msg_stats.h mynetworks.h mypwd.h namadr_list.h \
off_cvt.h opened.h own_inet_addr.h pipe_command.h post_mail.h \
qmgr_user.h qmqp_proto.h quote_821_local.h quote_822_local.h \
quote_flags.h rcpt_buf.h rcpt_print.h rec_attr_map.h rec_streamlf.h \
LIB_DIR = ../../lib
INC_DIR = ../../include
PLUGIN_MAP_SO = $(LIB_PREFIX)ldap$(LIB_SUFFIX) $(LIB_PREFIX)mysql$(LIB_SUFFIX) \
- $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX) \
- $(LIB_PREFIX)lmdb$(LIB_SUFFIX) $(LIB_PREFIX)cdb$(LIB_SUFFIX) \
- $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
+ $(LIB_PREFIX)pgsql$(LIB_SUFFIX) $(LIB_PREFIX)sqlite$(LIB_SUFFIX)
MAKES =
.c.o:; $(CC) $(SHLIB_CFLAGS) $(CFLAGS) -c $*.c
$(LIB_PREFIX)sqlite$(LIB_SUFFIX): dict_sqlite.o
$(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_sqlite.o $(AUXLIBS_SQLITE)
-$(LIB_PREFIX)cdb$(LIB_SUFFIX): mkmap_cdb.o $(LIB_DIR)/dict_cdb.o
- $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_cdb.o \
- $(LIB_DIR)/dict_cdb.o $(AUXLIBS_CDB)
-
-$(LIB_PREFIX)lmdb$(LIB_SUFFIX): mkmap_lmdb.o $(LIB_DIR)/dict_lmdb.o \
- $(LIB_DIR)/slmdb.o
- $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_lmdb.o $(LIB_DIR)/dict_lmdb.o \
- $(LIB_DIR)/slmdb.o $(AUXLIBS_LMDB)
-
-$(LIB_PREFIX)sdbm$(LIB_SUFFIX): mkmap_sdbm.o $(LIB_DIR)/dict_sdbm.o
- $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_sdbm.o \
- $(LIB_DIR)/dict_sdbm.o $(AUXLIBS_SDBM)
-
update: $(LIB_DIR)/$(LIB) $(HDRS) $(PLUGIN_MAP_SO_UPDATE)
-for i in $(HDRS); \
do \
data_redirect.o: ../../include/dict_db.h
data_redirect.o: ../../include/dict_dbm.h
data_redirect.o: ../../include/dict_lmdb.h
+data_redirect.o: ../../include/mkmap.h
data_redirect.o: ../../include/msg.h
data_redirect.o: ../../include/myflock.h
data_redirect.o: ../../include/name_code.h
dict_proxy.o: ../../include/dict.h
dict_proxy.o: ../../include/htable.h
dict_proxy.o: ../../include/iostuff.h
+dict_proxy.o: ../../include/mkmap.h
dict_proxy.o: ../../include/msg.h
dict_proxy.o: ../../include/myflock.h
dict_proxy.o: ../../include/mymalloc.h
dynamicmaps.o: ../../include/dict.h
dynamicmaps.o: ../../include/htable.h
dynamicmaps.o: ../../include/load_lib.h
+dynamicmaps.o: ../../include/mkmap.h
dynamicmaps.o: ../../include/msg.h
dynamicmaps.o: ../../include/myflock.h
dynamicmaps.o: ../../include/mymalloc.h
dynamicmaps.o: ../../include/vstring_vstream.h
dynamicmaps.o: dynamicmaps.c
dynamicmaps.o: dynamicmaps.h
-dynamicmaps.o: mkmap.h
ehlo_mask.o: ../../include/check_arg.h
ehlo_mask.o: ../../include/name_mask.h
ehlo_mask.o: ../../include/sys_defs.h
mail_dict.o: ../../include/argv.h
mail_dict.o: ../../include/check_arg.h
mail_dict.o: ../../include/dict.h
+mail_dict.o: ../../include/mkmap.h
mail_dict.o: ../../include/msg.h
mail_dict.o: ../../include/myflock.h
mail_dict.o: ../../include/mymalloc.h
mail_params.o: ../../include/inet_proto.h
mail_params.o: ../../include/iostuff.h
mail_params.o: ../../include/midna_domain.h
+mail_params.o: ../../include/mkmap.h
mail_params.o: ../../include/msg.h
mail_params.o: ../../include/msg_syslog.h
mail_params.o: ../../include/myaddrinfo.h
mail_params.o: ../../include/vstream.h
mail_params.o: ../../include/vstring.h
mail_params.o: ../../include/vstring_vstream.h
-mail_params.o: config_known_tcp_ports.h
mail_params.o: compat_level.h
+mail_params.o: config_known_tcp_ports.h
mail_params.o: mail_conf.h
mail_params.o: mail_params.c
mail_params.o: mail_params.h
mime_state.o: mime_state.c
mime_state.o: mime_state.h
mime_state.o: rec_type.h
-mkmap_cdb.o: ../../include/argv.h
-mkmap_cdb.o: ../../include/check_arg.h
-mkmap_cdb.o: ../../include/dict.h
-mkmap_cdb.o: ../../include/dict_cdb.h
-mkmap_cdb.o: ../../include/myflock.h
-mkmap_cdb.o: ../../include/mymalloc.h
-mkmap_cdb.o: ../../include/sys_defs.h
-mkmap_cdb.o: ../../include/vbuf.h
-mkmap_cdb.o: ../../include/vstream.h
-mkmap_cdb.o: ../../include/vstring.h
-mkmap_cdb.o: mkmap.h
-mkmap_cdb.o: mkmap_cdb.c
-mkmap_db.o: ../../include/argv.h
-mkmap_db.o: ../../include/check_arg.h
-mkmap_db.o: ../../include/dict.h
-mkmap_db.o: ../../include/dict_db.h
-mkmap_db.o: ../../include/msg.h
-mkmap_db.o: ../../include/myflock.h
-mkmap_db.o: ../../include/mymalloc.h
-mkmap_db.o: ../../include/stringops.h
-mkmap_db.o: ../../include/sys_defs.h
-mkmap_db.o: ../../include/vbuf.h
-mkmap_db.o: ../../include/vstream.h
-mkmap_db.o: ../../include/vstring.h
-mkmap_db.o: ../../include/warn_stat.h
-mkmap_db.o: mail_params.h
-mkmap_db.o: mkmap.h
-mkmap_db.o: mkmap_db.c
-mkmap_dbm.o: ../../include/argv.h
-mkmap_dbm.o: ../../include/check_arg.h
-mkmap_dbm.o: ../../include/dict.h
-mkmap_dbm.o: ../../include/dict_dbm.h
-mkmap_dbm.o: ../../include/msg.h
-mkmap_dbm.o: ../../include/myflock.h
-mkmap_dbm.o: ../../include/mymalloc.h
-mkmap_dbm.o: ../../include/stringops.h
-mkmap_dbm.o: ../../include/sys_defs.h
-mkmap_dbm.o: ../../include/vbuf.h
-mkmap_dbm.o: ../../include/vstream.h
-mkmap_dbm.o: ../../include/vstring.h
-mkmap_dbm.o: mkmap.h
-mkmap_dbm.o: mkmap_dbm.c
-mkmap_fail.o: ../../include/argv.h
-mkmap_fail.o: ../../include/check_arg.h
-mkmap_fail.o: ../../include/dict.h
-mkmap_fail.o: ../../include/dict_fail.h
-mkmap_fail.o: ../../include/myflock.h
-mkmap_fail.o: ../../include/mymalloc.h
-mkmap_fail.o: ../../include/sys_defs.h
-mkmap_fail.o: ../../include/vbuf.h
-mkmap_fail.o: ../../include/vstream.h
-mkmap_fail.o: ../../include/vstring.h
-mkmap_fail.o: mkmap.h
-mkmap_fail.o: mkmap_fail.c
-mkmap_lmdb.o: ../../include/argv.h
-mkmap_lmdb.o: ../../include/check_arg.h
-mkmap_lmdb.o: ../../include/dict.h
-mkmap_lmdb.o: ../../include/dict_lmdb.h
-mkmap_lmdb.o: ../../include/msg.h
-mkmap_lmdb.o: ../../include/myflock.h
-mkmap_lmdb.o: ../../include/mymalloc.h
-mkmap_lmdb.o: ../../include/stringops.h
-mkmap_lmdb.o: ../../include/sys_defs.h
-mkmap_lmdb.o: ../../include/vbuf.h
-mkmap_lmdb.o: ../../include/vstream.h
-mkmap_lmdb.o: ../../include/vstring.h
-mkmap_lmdb.o: ../../include/warn_stat.h
-mkmap_lmdb.o: mail_conf.h
-mkmap_lmdb.o: mail_params.h
-mkmap_lmdb.o: mkmap.h
-mkmap_lmdb.o: mkmap_lmdb.c
-mkmap_open.o: ../../include/argv.h
-mkmap_open.o: ../../include/check_arg.h
-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/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
-mkmap_open.o: ../../include/sigdelay.h
-mkmap_open.o: ../../include/stringops.h
-mkmap_open.o: ../../include/sys_defs.h
-mkmap_open.o: ../../include/vbuf.h
-mkmap_open.o: ../../include/vstream.h
-mkmap_open.o: ../../include/vstring.h
-mkmap_open.o: dict_proxy.h
-mkmap_open.o: mkmap.h
-mkmap_open.o: mkmap_open.c
mkmap_proxy.o: ../../include/argv.h
mkmap_proxy.o: ../../include/check_arg.h
mkmap_proxy.o: ../../include/dict.h
+mkmap_proxy.o: ../../include/mkmap.h
mkmap_proxy.o: ../../include/myflock.h
mkmap_proxy.o: ../../include/mymalloc.h
mkmap_proxy.o: ../../include/sys_defs.h
mkmap_proxy.o: ../../include/vstream.h
mkmap_proxy.o: ../../include/vstring.h
mkmap_proxy.o: dict_proxy.h
-mkmap_proxy.o: mkmap.h
mkmap_proxy.o: mkmap_proxy.c
-mkmap_sdbm.o: ../../include/argv.h
-mkmap_sdbm.o: ../../include/check_arg.h
-mkmap_sdbm.o: ../../include/dict.h
-mkmap_sdbm.o: ../../include/dict_sdbm.h
-mkmap_sdbm.o: ../../include/msg.h
-mkmap_sdbm.o: ../../include/myflock.h
-mkmap_sdbm.o: ../../include/mymalloc.h
-mkmap_sdbm.o: ../../include/stringops.h
-mkmap_sdbm.o: ../../include/sys_defs.h
-mkmap_sdbm.o: ../../include/vbuf.h
-mkmap_sdbm.o: ../../include/vstream.h
-mkmap_sdbm.o: ../../include/vstring.h
-mkmap_sdbm.o: mkmap.h
-mkmap_sdbm.o: mkmap_sdbm.c
msg_stats_print.o: ../../include/attr.h
msg_stats_print.o: ../../include/check_arg.h
msg_stats_print.o: ../../include/htable.h
const char *rite_str)
{
const char myname[] = "compat_relop_eval";
- long left_val, rite_val;
+ long left_val, rite_val, delta;
/*
* Negative result means error.
* Valid result. The difference between non-negative numbers will no
* overflow.
*/
- long delta = left_val - rite_val;
+ delta = left_val - rite_val;
switch (relop) {
case MAC_EXP_OP_TOK_EQ:
#define compat_level_from_major_minor(major, minor, msg_fn) \
compat_level_from_numbers((major), (minor), 0, (msg_fn))
-#
-
/* LICENSE
/* .ad
/* .fi
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_PROXY "proxy"
extern DICT *dict_proxy_open(const char *, int, int);
+extern MKMAP *mkmap_proxy_open(const char *);
/*
* Protocol interface.
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
/*
/* void dymap_init(const char *conf_path, const char *plugin_dir)
/* 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 a "dict_open"
-/* function for access to individual dictionary entries, and
-/* optionally the name of a "mkmap_open" function for bulk-mode
+/* This module reads the dynamicmaps.cf file and on-demand
+/* loads Postfix dictionaries. Each dynamicmaps.cf entry
+/* specifies the name of a dictionary type, the pathname of a
+/* shared-library object, the name of a "dict_open" function
+/* for access to individual dictionary entries, and optionally
+/* the name of a "mkmap_open" wrapper function for bulk-mode
/* dictionary creation. Plugins may be specified with a relative
/* pathname.
/*
-/* A dictionary may be installed without editing the file
-/* dynamicmaps.cf, by placing a configuration file under the
-/* directory dynamicmaps.cf.d, with the same format as
-/* dynamicmaps.cf.
+/* A dictionary shared object may be installed on a system
+/* without editing the file dynamicmaps.cf, by placing a
+/* configuration file under the directory dynamicmaps.cf.d,
+/* with the same format as dynamicmaps.cf.
/*
/* dymap_init() reads the specified configuration file which
-/* is in dynamicmaps.cf format, and hooks itself into the
-/* dict_open(), dict_mapnames(), and mkmap_open() functions.
+/* must be in dynamicmaps.cf format, appends ".d" to the path
+/* and scans the named directory for other configuration files,
+/* and on the first call hooks itself into the dict_open() and
+/* dict_mapnames() functions. All files are optional, but if
+/* an existing file cannot be opened, that is a fatal error.
/*
/* dymap_init() may be called multiple times during a process
/* lifetime, but it will not "unload" dictionaries that have
/*
/* Arguments:
/* .IP conf_path
-/* Pathname for the dynamicmaps configuration file.
+/* Pathname for the dynamicmaps configuration file. With ".d"
+/* appended, this becomes the pathname for a directory with
+/* other files in dynamicmaps.cf format.
/* .IP plugin_dir
/* Default directory for plugins with a relative pathname.
/* SEE ALSO
-/* load_lib(3) low-level run-time linker adapter
+/* load_lib(3) low-level run-time linker adapter.
/* DIAGNOSTICS
-/* Fatal errors: memory allocation problem, dictionary or
-/* dictionary function not available. Panic: invalid use.
+/* Warnings: unsupported dictionary type, shared object file
+/* does not exist, shared object permissions are not safe-for-root,
+/* configuration file permissions are not safe-for-root.
+/* Fatal errors: memory allocation problem, error opening an
+/* existing configuration file, bad configuration file syntax.
/* LICENSE
/* .ad
/* .fi
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/*
#include <htable.h>
#include <argv.h>
#include <dict.h>
+#include <mkmap.h>
#include <load_lib.h>
#include <vstring.h>
#include <vstream.h>
/*
* Global library.
*/
-#include <mkmap.h>
#include <dynamicmaps.h>
#ifdef USE_DYNAMIC_MAPS
static HTABLE *dymap_info;
static int dymap_hooks_done = 0;
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_dict_lookup - look up "dict_foo_open" function */
-static DICT_OPEN_FN dymap_dict_lookup(const char *dict_type)
+/* dymap_dict_lookup - look up DICT_OPEN_INFO */
+
+static const DICT_OPEN_INFO *dymap_dict_lookup(const char *dict_type)
{
+ const char myname[] = "dymap_dict_lookup";
struct stat st;
- LIB_FN fn[2];
- DICT_OPEN_FN dict_open_fn;
+ LIB_FN fn[3];
DYMAP_INFO *dp;
+ const DICT_OPEN_INFO *op;
+ DICT_OPEN_INFO *np;
+
+ if (msg_verbose > 1)
+ msg_info("%s: %s", myname, dict_type);
/*
* 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);
+ && (op = saved_dict_open_hook(dict_type)) != 0)
+ return (op);
/*
* Allow for graceful degradation when a database is unavailable. This
* allows Postfix daemon processes to continue handling email with
* reduced functionality.
*/
- if ((dp = (DYMAP_INFO *) htable_find(dymap_info, dict_type)) == 0)
+ if ((dp = (DYMAP_INFO *) htable_find(dymap_info, dict_type)) == 0) {
+ msg_warn("unsupported dictionary type: %s. "
+ "Is the postfix-%s package installed?",
+ dict_type, dict_type);
return (0);
+ }
if (stat(dp->soname, &st) < 0) {
msg_warn("unsupported dictionary type: %s (%s: %m)",
dict_type, dp->soname);
dict_type, dp->soname);
return (0);
}
- fn[0].name = dp->dict_name;
- fn[1].name = 0;
+ fn[0].name = dp->dict_name; /* not null */
+ fn[1].name = dp->mkmap_name; /* may be null */
+ fn[2].name = 0;
load_library_symbols(dp->soname, fn, (LIB_DP *) 0);
- return ((DICT_OPEN_FN) fn[0].fptr);
-}
-
-/* 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 the postmap(1) or postalias(1) command can't
- * create the requested database, then graceful degradation is not
- * useful.
- *
- * Fix 20220416: if this dictionary type is registered for some non-mkmap
- * purpose, then don't talk nonsense about a missing package.
- */
- if ((dp = (DYMAP_INFO *) htable_find(dymap_info, dict_type)) == 0) {
- ARGV *types = dict_mapnames();
- char **cpp;
-
- for (cpp = types->argv; *cpp; cpp++) {
- if (strcmp(dict_type, *cpp) == 0)
- msg_fatal("unsupported dictionary type: %s does not support "
- "bulk-mode creation.", dict_type);
- }
- 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: %m). "
- "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("unsupported dictionary type: %s "
- "(%s: file is owned or writable by non-root users)",
- dict_type, dp->soname);
- fn[0].name = dp->mkmap_name;
- fn[1].name = 0;
- load_library_symbols(dp->soname, fn, (LIB_DP *) 0);
- return ((MKMAP_OPEN_FN) fn[0].fptr);
+ np = (DICT_OPEN_INFO *) mymalloc(sizeof(*op));
+ np->type = mystrdup(dict_type);
+ np->dict_fn = (DICT_OPEN_FN) fn[0].fptr;
+ np->mkmap_fn = (MKMAP_OPEN_FN) (dp->mkmap_name ? fn[1].fptr : 0);
+ return (np);
}
/* dymap_list - enumerate dynamically-linked database type names */
static void dymap_read_conf(const char *path, const char *path_base)
{
+ const char myname[] = "dymap_read_conf";
VSTREAM *fp;
VSTRING *buf;
char *cp;
* Silently ignore a missing dynamicmaps.cf file, but be explicit about
* problems when the file does exist.
*/
+ if (msg_verbose > 1)
+ msg_info("%s: opening %s", myname, path);
if ((fp = vstream_fopen(path, O_RDONLY, 0)) != 0) {
if (fstat(vstream_fileno(fp), &st) < 0)
msg_fatal("%s: fstat failed; %m", path);
buf = vstring_alloc(100);
while (vstring_get_nonl(buf, fp) != VSTREAM_EOF) {
cp = vstring_str(buf);
+ if (msg_verbose > 1)
+ msg_info("%s: read: %s", myname, cp);
linenum++;
if (*cp == '#' || *cp == '\0')
continue;
vstring_free(buf);
/*
- * Once-only: hook into the dict_open(3) and mkmap_open(3)
- * infrastructure,
+ * Once-only: hook into the dict_open(3) infrastructure.
*/
if (dymap_hooks_done == 0) {
dymap_hooks_done = 1;
saved_dict_open_hook = dict_open_extend(dymap_dict_lookup);
- saved_mkmap_open_hook = mkmap_open_extend(dymap_mkmap_lookup);
saved_dict_mapnames_hook = dict_mapnames_extend(dymap_list);
}
}
const char *conf_name;
VSTRING *sub_conf_path;
+ if (msg_verbose > 1)
+ msg_info("%s: %s %s", myname, conf_path, plugin_dir);
+
/*
* Reload dynamicmaps.cf, but don't reload already-loaded plugins.
*/
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <mail_params.h>
#include <mail_dict.h>
-typedef struct {
- char *type;
- struct DICT *(*open) (const char *, int, int);
-} DICT_OPEN_INFO;
-
static const DICT_OPEN_INFO dict_open_info[] = {
- DICT_TYPE_PROXY, dict_proxy_open,
+ DICT_TYPE_PROXY, dict_proxy_open, mkmap_proxy_open,
#ifndef USE_DYNAMIC_MAPS
#ifdef HAS_LDAP
- DICT_TYPE_LDAP, dict_ldap_open,
+ DICT_TYPE_LDAP, dict_ldap_open, 0,
#endif
#ifdef HAS_MYSQL
- DICT_TYPE_MYSQL, dict_mysql_open,
+ DICT_TYPE_MYSQL, dict_mysql_open, 0,
#endif
#ifdef HAS_PGSQL
- DICT_TYPE_PGSQL, dict_pgsql_open,
+ DICT_TYPE_PGSQL, dict_pgsql_open, 0,
#endif
#ifdef HAS_SQLITE
- DICT_TYPE_SQLITE, dict_sqlite_open,
+ DICT_TYPE_SQLITE, dict_sqlite_open, 0,
#endif
#endif /* !USE_DYNAMIC_MAPS */
- DICT_TYPE_MEMCACHE, dict_memcache_open,
+ DICT_TYPE_MEMCACHE, dict_memcache_open, 0,
0,
};
#endif
for (dp = dict_open_info; dp->type; dp++)
- dict_open_register(dp->type, dp->open);
+ dict_open_register(dp);
}
#ifdef TEST
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20220421"
+#define MAIL_RELEASE_DATE "20220507"
#define MAIL_VERSION_NUMBER "3.8"
#ifdef SNAPSHOT
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
+++ /dev/null
-#ifndef _MKMAP_H_INCLUDED_
-#define _MKMAP_H_INCLUDED_
-
-/*++
-/* NAME
-/* mkmap 3h
-/* SUMMARY
-/* create or rewrite Postfix database
-/* SYNOPSIS
-/* #include <mkmap.h>
-/* DESCRIPTION
-/* .nf
-
- /*
- * Utility library.
- */
-#include <dict.h>
-
- /*
- * A database handle is an opaque structure. The user is not supposed to
- * know its implementation. We try to open and lock a file before DB/DBM
- * initialization. However, if the file does not exist then we may have to
- * acquire the lock after the DB/DBM initialization.
- */
-typedef struct MKMAP {
- 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 */
-} MKMAP;
-
-extern MKMAP *mkmap_open(const char *, const char *, int, int);
-extern void mkmap_append(MKMAP *, const char *, const char *);
-extern void mkmap_close(MKMAP *);
-
-#define mkmap_append(map, key, val) dict_put((map)->dict, (key), (val))
-
-extern MKMAP *mkmap_dbm_open(const char *);
-extern MKMAP *mkmap_cdb_open(const char *);
-extern MKMAP *mkmap_hash_open(const char *);
-extern MKMAP *mkmap_btree_open(const char *);
-extern MKMAP *mkmap_lmdb_open(const char *);
-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
-/* The Secure Mailer license must be distributed with this software.
-/* AUTHOR(S)
-/* Wietse Venema
-/* IBM T.J. Watson Research
-/* P.O. Box 704
-/* Yorktown Heights, NY 10598, USA
-/*--*/
-
-#endif
/* SUMMARY
/* create or proxied database
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_proxy.h>
/*
/* MKMAP *mkmap_proxy_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <mymalloc.h>
#include <dict_proxy.h>
-/* Application-specific. */
-
-#include "mkmap.h"
-
/* mkmap_proxy_open - create or open database */
MKMAP *mkmap_proxy_open(const char *unused_path)
postalias.o: ../../include/check_arg.h
postalias.o: ../../include/clean_env.h
postalias.o: ../../include/dict.h
+postalias.o: ../../include/dict_db.h
postalias.o: ../../include/dict_proxy.h
postalias.o: ../../include/mail_conf.h
postalias.o: ../../include/mail_dict.h
#include <set_eugid.h>
#include <warn_stat.h>
#include <clean_env.h>
+#include <dict_db.h>
/* Global library. */
#include <mail_dict.h>
#include <mail_params.h>
#include <mail_version.h>
-#include <mkmap.h>
#include <mail_task.h>
#include <dict_proxy.h>
#include <mail_parm_split.h>
&& (st.st_uid != geteuid() || st.st_gid != getegid()))
set_eugid(st.st_uid, st.st_gid);
+ /*
+ * Override the default per-table cache size for DB map (re)builds. We
+ * can't do this in the mkmap* functions because those don't have access
+ * to Postfix parameter settings.
+ *
+ * db_cache_size" is defined in util/dict_open.c and defaults to 128kB,
+ * which works well for the lookup code.
+ *
+ * We use a larger per-table cache when building ".db" files. For "hash"
+ * files performance degrades rapidly unless the memory pool is O(file
+ * size).
+ *
+ * For "btree" files performance is good with sorted input even for small
+ * memory pools, but with random input degrades rapidly unless the memory
+ * pool is O(file size).
+ */
+ dict_db_cache_size = var_db_create_buf;
+
/*
* Open the database, create it when it does not exist, truncate it when
* it does exist, and lock out any spectators.
postconf_dbms.o: ../../include/mac_parse.h
postconf_dbms.o: ../../include/mail_conf.h
postconf_dbms.o: ../../include/mail_params.h
+postconf_dbms.o: ../../include/mkmap.h
postconf_dbms.o: ../../include/msg.h
postconf_dbms.o: ../../include/myflock.h
postconf_dbms.o: ../../include/mymalloc.h
postmap.o: ../../include/check_arg.h
postmap.o: ../../include/clean_env.h
postmap.o: ../../include/dict.h
+postmap.o: ../../include/dict_db.h
postmap.o: ../../include/dict_proxy.h
postmap.o: ../../include/header_opts.h
postmap.o: ../../include/mail_conf.h
#include <set_eugid.h>
#include <warn_stat.h>
#include <clean_env.h>
+#include <dict_db.h>
/* Global library. */
#include <mail_dict.h>
#include <mail_params.h>
#include <mail_version.h>
-#include <mkmap.h>
#include <mail_task.h>
#include <dict_proxy.h>
#include <mime_state.h>
&& (st.st_uid != geteuid() || st.st_gid != getegid()))
set_eugid(st.st_uid, st.st_gid);
+ /*
+ * Override the default per-table cache size for DB map (re)builds. We
+ * can't do this in the mkmap* functions because those don't have access
+ * to Postfix parameter settings.
+ *
+ * db_cache_size" is defined in util/dict_open.c and defaults to 128kB,
+ * which works well for the lookup code.
+ *
+ * We use a larger per-table cache when building ".db" files. For "hash"
+ * files performance degrades rapidly unless the memory pool is O(file
+ * size).
+ *
+ * For "btree" files performance is good with sorted input even for small
+ * memory pools, but with random input degrades rapidly unless the memory
+ * pool is O(file size).
+ */
+ dict_db_cache_size = var_db_create_buf;
+
/*
* Open the database, optionally create it when it does not exist,
* optionally truncate it when it does exist, and lock out any
dicts[n] = 0;
/*
- * Perform all queries. Open maps on the fly, to avoid opening unnecessary
- * maps.
+ * Perform all queries. Open maps on the fly, to avoid opening
+ * unnecessary maps.
*/
if ((postmap_flags & POSTMAP_FLAG_HB_KEY) == 0) {
while (vstring_get_nonl(keybuf, in) != VSTREAM_EOF) {
* unavailable when tlsproxy(8) detects the problem too late.
*/
if (PSC_SMTPD_NEXT_TOKEN(args) != 0)
- return (PSC_SEND_REPLY(state, "501 Syntax: EHLO hostname\r\n"));
+ return (PSC_SEND_REPLY(state, "501 5.5.4 Syntax: STARTTLS\r\n"));
if (state->flags & PSC_STATE_FLAG_USING_TLS)
return (PSC_SEND_REPLY(state,
"554 5.5.1 Error: TLS already active\r\n"));
proxymap.o: ../../include/mail_proto.h
proxymap.o: ../../include/mail_server.h
proxymap.o: ../../include/mail_version.h
+proxymap.o: ../../include/mkmap.h
proxymap.o: ../../include/msg.h
proxymap.o: ../../include/myflock.h
proxymap.o: ../../include/mymalloc.h
smtp_sasl_auth_cache.o: ../../include/maps.h
smtp_sasl_auth_cache.o: ../../include/match_list.h
smtp_sasl_auth_cache.o: ../../include/mime_state.h
+smtp_sasl_auth_cache.o: ../../include/mkmap.h
smtp_sasl_auth_cache.o: ../../include/msg.h
smtp_sasl_auth_cache.o: ../../include/msg_stats.h
smtp_sasl_auth_cache.o: ../../include/myaddrinfo.h
split_qnameval.c argv_attr_print.c argv_attr_scan.c dict_file.c \
msg_logger.c logwriter.c unix_dgram_connect.c unix_dgram_listen.c \
byte_mask.c known_tcp_ports.c argv_split_at.c dict_stream.c \
- sane_strtol.c hash_fnv.c ldseed.c
+ sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
+ mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c
OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
split_qnameval.o argv_attr_print.o argv_attr_scan.o dict_file.o \
msg_logger.o logwriter.o unix_dgram_connect.o unix_dgram_listen.o \
byte_mask.o known_tcp_ports.o argv_split_at.o dict_stream.o \
- sane_strtol.o hash_fnv.o ldseed.o
+ sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
+ mkmap_fail.o mkmap_open.o
# MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
# When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
# otherwise it sets the PLUGIN_* macros.
-MAP_OBJ = dict_pcre.o $(LIB_MAP_OBJ)
-LIB_MAP_OBJ = dict_cdb.o dict_lmdb.o dict_sdbm.o slmdb.o
+MAP_OBJ = dict_pcre.o dict_cdb.o dict_lmdb.o dict_sdbm.o slmdb.o \
+ mkmap_cdb.o mkmap_lmdb.o mkmap_sdbm.o
HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \
dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \
slmdb.h compat_va_copy.h dict_pipe.h dict_random.h \
valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
check_arg.h argv_attr.h msg_logger.h logwriter.h byte_mask.h \
- known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h
+ known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h
TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \
stream_test.c dup2_pass_on_exec.c
DEFS = -I. -D$(SYSTYPE)
valid_utf8_string ip_match base32_code msg_rate_delay netstring \
vstream timecmp dict_cache midna_domain casefold strcasecmp_utf8 \
vbuf_print split_qnameval vstream msg_logger byte_mask \
- known_tcp_ports dict_stream find_inet binhash hash_fnv
-PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX)
+ known_tcp_ports dict_stream find_inet binhash hash_fnv argv
+PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \
+ $(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
HTABLE_FIX = NORANDOMIZE=1
LIB_DIR = ../../lib
INC_DIR = ../../include
$(LIB_PREFIX)pcre$(LIB_SUFFIX): dict_pcre.o
$(PLUGIN_LD) $(SHLIB_RPATH) -o $@ dict_pcre.o $(AUXLIBS_PCRE)
+$(LIB_PREFIX)cdb$(LIB_SUFFIX): mkmap_cdb.o dict_cdb.o
+ $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_cdb.o \
+ dict_cdb.o $(AUXLIBS_CDB)
+
+$(LIB_PREFIX)lmdb$(LIB_SUFFIX): mkmap_lmdb.o dict_lmdb.o slmdb.o
+ $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_lmdb.o dict_lmdb.o \
+ slmdb.o $(AUXLIBS_LMDB)
+
+$(LIB_PREFIX)sdbm$(LIB_SUFFIX): mkmap_sdbm.o dict_sdbm.o
+ $(PLUGIN_LD) $(SHLIB_RPATH) -o $@ mkmap_sdbm.o \
+ dict_sdbm.o $(AUXLIBS_SDBM)
+
update: $(LIB_DIR)/$(LIB) $(HDRS) $(PLUGIN_MAP_SO_UPDATE) \
$(PLUGIN_MAP_OBJ_UPDATE)
-for i in $(HDRS); \
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
mv junk $@.o
+argv: $(LIB)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+ mv junk $@.o
+
tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
hex_quote_test ctable_test inet_addr_list_test base64_code_test \
- attr_scan64_test attr_scan0_test dict_pcre_tests host_port_test \
- dict_cidr_test attr_scan_plain_test htable_test hex_code_test \
- myaddrinfo_test format_tv_test ip_match_test name_mask_tests \
- base32_code_test dict_thash_test surrogate_test timecmp_test \
- dict_static_test dict_inline_test midna_domain_test casefold_test \
- dict_utf8_test strcasecmp_utf8_test vbuf_print_test dict_regexp_test \
- dict_union_test dict_pipe_test miss_endif_cidr_test \
+ attr_scan64_test attr_scan0_test host_port_test dict_tests \
+ attr_scan_plain_test htable_test hex_code_test myaddrinfo_test \
+ format_tv_test ip_match_test name_mask_tests base32_code_test \
+ surrogate_test timecmp_test midna_domain_test casefold_test \
+ strcasecmp_utf8_test vbuf_print_test miss_endif_cidr_test \
miss_endif_regexp_test split_qnameval_test vstring_test \
- vstream_test dict_regexp_file_test dict_cidr_file_test \
+ vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \
+ binhash_test argv_test
+
+dict_tests: all dict_test \
+ dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
+ dict_inline_test dict_utf8_test dict_regexp_test dict_union_test \
+ dict_pipe_test dict_regexp_file_test dict_cidr_file_test \
dict_static_file_test dict_random_test dict_random_file_test \
- dict_inline_file_test byte_mask_tests mystrtok_test \
- known_tcp_ports_test dict_stream_test dict_inline_regexp_test \
- dict_inline_cidr_test binhash_test
+ dict_inline_file_test dict_stream_test dict_inline_regexp_test \
+ dict_inline_cidr_test
dict_pcre_tests: dict_pcre_test miss_endif_pcre_test dict_pcre_file_test \
dict_inline_pcre_test
rm -f dict_inline_cidr.tmp
find_inet_test: find_inet find_inet.ref
- $(SHLIB_ENV) ${VALGRIND} ./find_inet >find_inet.tmp 2>&1
+ $(SHLIB_ENV) ${VALGRIND} ./find_inet >find_inet.tmp 2>&1
diff find_inet.ref find_inet.tmp
rm -f find_inet.tmp
+argv_test: argv
+ $(SHLIB_ENV) ${VALGRIND} ./argv
+
depend: $(MAKES)
(sed '1,/^# do not edit/!d' Makefile.in; \
set -e; for i in [a-z][a-z0-9]*.c; do \
dict_cdb.o: dict_cdb.c
dict_cdb.o: dict_cdb.h
dict_cdb.o: iostuff.h
+dict_cdb.o: mkmap.h
dict_cdb.o: msg.h
dict_cdb.o: myflock.h
dict_cdb.o: mymalloc.h
dict_db.o: dict_db.c
dict_db.o: dict_db.h
dict_db.o: iostuff.h
+dict_db.o: mkmap.h
dict_db.o: msg.h
dict_db.o: myflock.h
dict_db.o: mymalloc.h
dict_fail.o: dict.h
dict_fail.o: dict_fail.c
dict_fail.o: dict_fail.h
+dict_fail.o: mkmap.h
dict_fail.o: msg.h
dict_fail.o: myflock.h
dict_fail.o: mymalloc.h
dict_lmdb.o: dict_lmdb.h
dict_lmdb.o: htable.h
dict_lmdb.o: iostuff.h
+dict_lmdb.o: mkmap.h
dict_lmdb.o: msg.h
dict_lmdb.o: myflock.h
dict_lmdb.o: mymalloc.h
dict_open.o: dict_union.h
dict_open.o: dict_unix.h
dict_open.o: htable.h
+dict_open.o: mkmap.h
dict_open.o: msg.h
dict_open.o: myflock.h
dict_open.o: mymalloc.h
dict_sdbm.o: dict_sdbm.h
dict_sdbm.o: htable.h
dict_sdbm.o: iostuff.h
+dict_sdbm.o: mkmap.h
dict_sdbm.o: msg.h
dict_sdbm.o: myflock.h
dict_sdbm.o: mymalloc.h
dict_test.o: dict_db.h
dict_test.o: dict_lmdb.h
dict_test.o: dict_test.c
+dict_test.o: mkmap.h
dict_test.o: msg.h
dict_test.o: msg_vstream.h
dict_test.o: myflock.h
midna_domain.o: valid_hostname.h
midna_domain.o: vbuf.h
midna_domain.o: vstring.h
+mkmap_cdb.o: argv.h
+mkmap_cdb.o: check_arg.h
+mkmap_cdb.o: dict.h
+mkmap_cdb.o: dict_cdb.h
+mkmap_cdb.o: mkmap.h
+mkmap_cdb.o: mkmap_cdb.c
+mkmap_cdb.o: myflock.h
+mkmap_cdb.o: mymalloc.h
+mkmap_cdb.o: sys_defs.h
+mkmap_cdb.o: vbuf.h
+mkmap_cdb.o: vstream.h
+mkmap_cdb.o: vstring.h
+mkmap_db.o: argv.h
+mkmap_db.o: check_arg.h
+mkmap_db.o: dict.h
+mkmap_db.o: dict_db.h
+mkmap_db.o: mkmap.h
+mkmap_db.o: mkmap_db.c
+mkmap_db.o: msg.h
+mkmap_db.o: myflock.h
+mkmap_db.o: mymalloc.h
+mkmap_db.o: stringops.h
+mkmap_db.o: sys_defs.h
+mkmap_db.o: vbuf.h
+mkmap_db.o: vstream.h
+mkmap_db.o: vstring.h
+mkmap_db.o: warn_stat.h
+mkmap_dbm.o: argv.h
+mkmap_dbm.o: check_arg.h
+mkmap_dbm.o: dict.h
+mkmap_dbm.o: dict_dbm.h
+mkmap_dbm.o: mkmap.h
+mkmap_dbm.o: mkmap_dbm.c
+mkmap_dbm.o: msg.h
+mkmap_dbm.o: myflock.h
+mkmap_dbm.o: mymalloc.h
+mkmap_dbm.o: stringops.h
+mkmap_dbm.o: sys_defs.h
+mkmap_dbm.o: vbuf.h
+mkmap_dbm.o: vstream.h
+mkmap_dbm.o: vstring.h
+mkmap_fail.o: argv.h
+mkmap_fail.o: check_arg.h
+mkmap_fail.o: dict.h
+mkmap_fail.o: dict_fail.h
+mkmap_fail.o: mkmap.h
+mkmap_fail.o: mkmap_fail.c
+mkmap_fail.o: myflock.h
+mkmap_fail.o: mymalloc.h
+mkmap_fail.o: sys_defs.h
+mkmap_fail.o: vbuf.h
+mkmap_fail.o: vstream.h
+mkmap_fail.o: vstring.h
+mkmap_lmdb.o: argv.h
+mkmap_lmdb.o: check_arg.h
+mkmap_lmdb.o: dict.h
+mkmap_lmdb.o: dict_lmdb.h
+mkmap_lmdb.o: mkmap.h
+mkmap_lmdb.o: mkmap_lmdb.c
+mkmap_lmdb.o: myflock.h
+mkmap_lmdb.o: mymalloc.h
+mkmap_lmdb.o: sys_defs.h
+mkmap_lmdb.o: vbuf.h
+mkmap_lmdb.o: vstream.h
+mkmap_lmdb.o: vstring.h
+mkmap_open.o: argv.h
+mkmap_open.o: check_arg.h
+mkmap_open.o: dict.h
+mkmap_open.o: mkmap.h
+mkmap_open.o: mkmap_open.c
+mkmap_open.o: msg.h
+mkmap_open.o: myflock.h
+mkmap_open.o: mymalloc.h
+mkmap_open.o: sigdelay.h
+mkmap_open.o: stringops.h
+mkmap_open.o: sys_defs.h
+mkmap_open.o: vbuf.h
+mkmap_open.o: vstream.h
+mkmap_open.o: vstring.h
+mkmap_sdbm.o: argv.h
+mkmap_sdbm.o: check_arg.h
+mkmap_sdbm.o: dict.h
+mkmap_sdbm.o: dict_sdbm.h
+mkmap_sdbm.o: mkmap.h
+mkmap_sdbm.o: mkmap_sdbm.c
+mkmap_sdbm.o: msg.h
+mkmap_sdbm.o: myflock.h
+mkmap_sdbm.o: mymalloc.h
+mkmap_sdbm.o: stringops.h
+mkmap_sdbm.o: sys_defs.h
+mkmap_sdbm.o: vbuf.h
+mkmap_sdbm.o: vstream.h
+mkmap_sdbm.o: vstring.h
msg.o: msg.c
msg.o: msg.h
msg.o: msg_output.h
/* SYNOPSIS
/* #include <argv.h>
/*
+/* typedef int (*ARGV_COMPAR_FN)(const void *, const void *);
+/*
/* ARGV *argv_alloc(len)
/* ssize_t len;
/*
-/* ARGV *argv_sort(argvp)
+/* ARGV *argv_qsort(argvp, compar)
/* ARGV *argvp;
+/* ARGV_COMPAR_FN compar;
+/*
+/* void argv_uniq(argvp, compar)
+/* ARGV *argvp;
+/* ARGV_COMPAR_FN compar;
/*
/* ARGV *argv_free(argvp)
/* ARGV *argvp;
/* length. The result is ready for use by argv_add(). The array
/* is null terminated.
/*
-/* argv_sort() sorts the elements of argvp in place returning
-/* the original array.
+/* argv_qsort() sorts the elements of argvp in place, and
+/* returns its first argument. If the compar argument specifies
+/* a null pointer, then argv_qsort() will use byte-by-byte
+/* comparison.
+/*
+/* argv_uniq() reduces adjacent same-value elements to one
+/* element, and returns its first argument. If the compar
+/* argument specifies a null pointer, then argv_uniq() will
+/* use byte-by-byte comparison.
/*
/* argv_add() copies zero or more strings and adds them to the
/* specified string array. The array is null terminated.
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System libraries. */
#include "msg.h"
#include "argv.h"
+#ifdef TEST
+extern NORETURN PRINTFLIKE(1, 2) test_msg_panic(const char *,...);
+
+#define msg_panic test_msg_panic
+#endif
+
/* argv_free - destroy string array */
ARGV *argv_free(ARGV *argvp)
return strcmp(s1, s2);
}
-/* argv_sort - sort array in place */
+/* argv_qsort - sort array in place */
+
+ARGV *argv_qsort(ARGV *argvp, ARGV_COMPAR_FN compar)
+{
+ qsort(argvp->argv, argvp->argc, sizeof(argvp->argv[0]),
+ compar ? compar : argv_cmp);
+ return (argvp);
+}
+
+/* argv_sort - binary compatibility */
ARGV *argv_sort(ARGV *argvp)
{
return (argvp);
}
+/* argv_uniq - deduplicate adjacent array elements */
+
+ARGV *argv_uniq(ARGV *argvp, ARGV_COMPAR_FN compar)
+{
+ char **cpp;
+ char **prev;
+
+ if (compar == 0)
+ compar = argv_cmp;
+ for (prev = 0, cpp = argvp->argv; cpp < argvp->argv + argvp->argc; cpp++) {
+ if (prev != 0 && compar(prev, cpp) == 0) {
+ argv_delete(argvp, cpp - argvp->argv, 1);
+ cpp = prev;
+ } else {
+ prev = cpp;
+ }
+ }
+ return (argvp);
+}
+
/* argv_extend - extend array */
static void argv_extend(ARGV *argvp)
argvp->argv[pos] = argvp->argv[pos + how_many];
argvp->argc -= how_many;
}
+
+#ifdef TEST
+
+ /*
+ * System library.
+ */
+#include <setjmp.h>
+
+ /*
+ * Utility library.
+ */
+#include <msg_vstream.h>
+#include <stringops.h>
+
+#define ARRAY_LEN (10)
+
+typedef struct TEST_CASE {
+ const char *label; /* identifies test case */
+ const char *inputs[ARRAY_LEN]; /* input strings */
+ int terminate; /* terminate result */
+ ARGV *(*populate_fn) (const struct TEST_CASE *, ARGV *);
+ const char *exp_panic_msg; /* expected panic */
+ int exp_argc; /* expected array length */
+ const char *exp_argv[ARRAY_LEN]; /* expected array content */
+} TEST_CASE;
+
+#define TERMINATE_ARRAY (1)
+
+#define PASS (0)
+#define FAIL (1)
+
+VSTRING *test_panic_str;
+jmp_buf test_panic_jbuf;
+
+/* test_msg_panic - does not return, and does not terminate */
+
+void test_msg_panic(const char *fmt,...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ test_panic_str = vstring_alloc(100);
+ vstring_vsprintf(test_panic_str, fmt, ap);
+ va_end(ap);
+ longjmp(test_panic_jbuf, 1);
+}
+
+/* test_argv_populate - populate result, optionally terminate */
+
+static ARGV *test_argv_populate(const TEST_CASE *tp, ARGV *argvp)
+{
+ const char *const * cpp;
+
+ for (cpp = tp->inputs; *cpp; cpp++)
+ argv_add(argvp, *cpp, (char *) 0);
+ if (tp->terminate)
+ argv_terminate(argvp);
+ return (argvp);
+}
+
+/* test_argv_sort - populate and sort result */
+
+static ARGV *test_argv_sort(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_qsort(argvp, (ARGV_COMPAR_FN) 0);
+ return (argvp);
+}
+
+/* test_argv_sort_uniq - populate, sort, uniq result */
+
+static ARGV *test_argv_sort_uniq(const TEST_CASE *tp, ARGV *argvp)
+{
+
+ /*
+ * This also tests argv_delete().
+ */
+ test_argv_sort(tp, argvp);
+ argv_uniq(argvp, (ARGV_COMPAR_FN) 0);
+ return (argvp);
+}
+
+/* test_argv_good_truncate - populate and truncate to good size */
+
+static ARGV *test_argv_good_truncate(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_truncate(argvp, tp->exp_argc);
+ return (argvp);
+}
+
+/* test_argv_bad_truncate - populate and truncate to bad size */
+
+static ARGV *test_argv_bad_truncate(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_truncate(argvp, -1);
+ return (argvp);
+}
+
+/* test_argv_good_insert - populate and insert at good position */
+
+static ARGV *test_argv_good_insert(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_insert_one(argvp, 1, "new");
+ return (argvp);
+}
+
+/* test_argv_bad_insert1 - populate and insert at bad position */
+
+static ARGV *test_argv_bad_insert1(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_insert_one(argvp, -1, "new");
+ return (argvp);
+}
+
+/* test_argv_bad_insert2 - populate and insert at bad position */
+
+static ARGV *test_argv_bad_insert2(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_insert_one(argvp, 100, "new");
+ return (argvp);
+}
+
+/* test_argv_good_replace - populate and replace at good position */
+
+static ARGV *test_argv_good_replace(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_replace_one(argvp, 1, "new");
+ return (argvp);
+}
+
+/* test_argv_bad_replace1 - populate and replace at bad position */
+
+static ARGV *test_argv_bad_replace1(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_replace_one(argvp, -1, "new");
+ return (argvp);
+}
+
+/* test_argv_bad_replace2 - populate and replace at bad position */
+
+static ARGV *test_argv_bad_replace2(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_replace_one(argvp, 100, "new");
+ return (argvp);
+}
+
+/* test_argv_bad_delete1 - populate and delete at bad position */
+
+static ARGV *test_argv_bad_delete1(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_delete(argvp, -1, 1);
+ return (argvp);
+}
+
+/* test_argv_bad_delete2 - populate and delete at bad position */
+
+static ARGV *test_argv_bad_delete2(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_delete(argvp, 0, -1);
+ return (argvp);
+}
+
+/* test_argv_bad_delete3 - populate and delete at bad position */
+
+static ARGV *test_argv_bad_delete3(const TEST_CASE *tp, ARGV *argvp)
+{
+ test_argv_populate(tp, argvp);
+ argv_delete(argvp, 100, 1);
+ return (argvp);
+}
+
+/* test_argv_verify - verify result */
+
+static int test_argv_verify(const TEST_CASE *tp, ARGV *argvp)
+{
+ int idx;
+
+ if (tp->exp_panic_msg != 0) {
+ if (test_panic_str == 0) {
+ msg_warn("test case '%s': got no panic, want: '%s'",
+ tp->label, tp->exp_panic_msg);
+ return (FAIL);
+ }
+ if (strcmp(vstring_str(test_panic_str), tp->exp_panic_msg) != 0) {
+ msg_warn("test case '%s': got '%s', want: '%s'",
+ tp->label, vstring_str(test_panic_str), tp->exp_panic_msg);
+ return (FAIL);
+ }
+ return (PASS);
+ }
+ if (test_panic_str != 0) {
+ msg_warn("test case '%s': got '%s', want: no panic",
+ tp->label, vstring_str(test_panic_str));
+ return (FAIL);
+ }
+ if (argvp->argc != tp->exp_argc) {
+ msg_warn("test case '%s': got argc: %ld, want: %d",
+ tp->label, (long) argvp->argc, tp->exp_argc);
+ return (FAIL);
+ }
+ if (argvp->argv[argvp->argc] != 0 && tp->terminate) {
+ msg_warn("test case '%s': got unterminated, want: terminated", tp->label);
+ return (FAIL);
+ }
+ for (idx = 0; idx < argvp->argc; idx++) {
+ if (strcmp(argvp->argv[idx], tp->exp_argv[idx]) != 0) {
+ msg_warn("test case '%s': index %d: got '%s', want: '%s'",
+ tp->label, idx, argvp->argv[idx], tp->exp_argv[idx]);
+ return (FAIL);
+ }
+ }
+ return (PASS);
+}
+
+ /*
+ * The test cases. TODO: argv_addn with good and bad string length.
+ */
+static const TEST_CASE test_cases[] = {
+ {"multiple strings, unterminated array",
+ {"foo", "baz", "bar", 0}, 0, test_argv_populate,
+ 0, 3, {"foo", "baz", "bar", 0}
+ },
+ {"multiple strings, terminated array",
+ {"foo", "baz", "bar", 0}, TERMINATE_ARRAY, test_argv_populate,
+ 0, 3, {"foo", "baz", "bar", 0}
+ },
+ {"distinct strings, sorted array",
+ {"foo", "baz", "bar", 0}, 0, test_argv_sort,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted array",
+ {"foo", "baz", "baz", "bar", 0}, 0, test_argv_sort,
+ 0, 4, {"bar", "baz", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-middle elements",
+ {"foo", "baz", "baz", "bar", 0}, 0, test_argv_sort_uniq,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-first elements",
+ {"foo", "bar", "baz", "bar", 0}, 0, test_argv_sort_uniq,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"duplicate strings, sorted, uniqued-last elements",
+ {"foo", "foo", "baz", "bar", 0}, 0, test_argv_sort_uniq,
+ 0, 3, {"bar", "baz", "foo", 0}
+ },
+ {"multiple strings, truncate array by one",
+ {"foo", "baz", "bar", 0}, 0, test_argv_good_truncate,
+ 0, 2, {"foo", "baz", 0}
+ },
+ {"multiple strings, truncate whole array",
+ {"foo", "baz", "bar", 0}, 0, test_argv_good_truncate,
+ 0, 0, {"foo", "baz", 0}
+ },
+ {"multiple strings, bad truncate",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_truncate,
+ "argv_truncate: bad length -1"
+ },
+ {"multiple strings, insert one at good position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_good_insert,
+ 0, 4, {"foo", "new", "baz", "bar", 0}
+ },
+ {"multiple strings, insert one at bad position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_insert1,
+ "argv_insert_one bad position: -1"
+ },
+ {"multiple strings, insert one at bad position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_insert2,
+ "argv_insert_one bad position: 100"
+ },
+ {"multiple strings, replace one at good position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_good_replace,
+ 0, 3, {"foo", "new", "bar", 0}
+ },
+ {"multiple strings, replace one at bad position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_replace1,
+ "argv_replace_one bad position: -1"
+ },
+ {"multiple strings, replace one at bad position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_replace2,
+ "argv_replace_one bad position: 100"
+ },
+ {"multiple strings, delete one at negative position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete1,
+ "argv_delete bad range: (start=-1 count=1)"
+ },
+ {"multiple strings, delete with bad range end",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete2,
+ "argv_delete bad range: (start=0 count=-1)"
+ },
+ {"multiple strings, delete at too large position",
+ {"foo", "baz", "bar", 0}, 0, test_argv_bad_delete3,
+ "argv_delete bad range: (start=100 count=1)"
+ },
+ 0,
+};
+
+int main(int argc, char **argv)
+{
+ const TEST_CASE *tp;
+ int pass = 0;
+ int fail = 0;
+
+ msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+ for (tp = test_cases; tp->label != 0; tp++) {
+ int test_failed;
+ ARGV *argvp;
+
+ argvp = argv_alloc(1);
+ if (setjmp(test_panic_jbuf) == 0)
+ tp->populate_fn(tp, argvp);
+ test_failed = test_argv_verify(tp, argvp);
+ if (test_failed) {
+ msg_info("%s: FAIL", tp->label);
+ fail++;
+ } else {
+ msg_info("%s: PASS", tp->label);
+ pass++;
+ }
+ argv_free(argvp);
+ if (test_panic_str) {
+ vstring_free(test_panic_str);
+ test_panic_str = 0;
+ }
+ }
+ msg_info("PASS=%d FAIL=%d", pass, fail);
+ exit(fail != 0);
+}
+
+#endif
char **argv; /* string array */
} ARGV;
+typedef int (*ARGV_COMPAR_FN)(const void *, const void *);
+
extern ARGV *argv_alloc(ssize_t);
-extern ARGV *argv_sort(ARGV *);
+extern ARGV *argv_sort(ARGV *); /* backwards compatibility */
+extern ARGV *argv_qsort(ARGV *, ARGV_COMPAR_FN);
+extern ARGV *argv_uniq(ARGV *, ARGV_COMPAR_FN);
extern void argv_add(ARGV *,...);
extern void argv_addn(ARGV *,...);
extern void argv_terminate(ARGV *);
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System libraries. */
* 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 *);
+typedef struct {
+ const char *type;
+ DICT_OPEN_FN dict_fn;
+ struct MKMAP *(*mkmap_fn) (const char *);
+} DICT_OPEN_INFO;
+typedef const DICT_OPEN_INFO *(*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_OPEN_FN);
+extern void dict_open_register(const DICT_OPEN_INFO *);
+extern const DICT_OPEN_INFO *dict_open_lookup(const char *);
extern DICT_OPEN_EXTEND_FN dict_open_extend(DICT_OPEN_EXTEND_FN);
#define dict_get(dp, key) ((const char *) (dp)->lookup((dp), (key)))
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_CDB "cdb"
extern DICT *dict_cdb_open(const char *, int, int);
+extern MKMAP *mkmap_cdb_open(const char *);
/* LICENSE
/* .ad
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif /* _DICT_CDB_H_INCLUDED_ */
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
extern DICT *dict_hash_open(const char *, int, int);
extern DICT *dict_btree_open(const char *, int, int);
+extern MKMAP *mkmap_hash_open(const char *);
+extern MKMAP *mkmap_btree_open(const char *);
/*
* XXX Should be part of the DICT interface.
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_DBM "dbm"
extern DICT *dict_dbm_open(const char *, int, int);
+extern MKMAP *mkmap_dbm_open(const char *);
/* LICENSE
/* .ad
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_FAIL "fail"
extern DICT *dict_fail_open(const char *, int, int);
+extern MKMAP *mkmap_fail_open(const char *);
/* LICENSE
/* .ad
/* AUTHOR(S)
/* jeffm
/* ghostgun.com
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_LMDB "lmdb"
extern DICT *dict_lmdb_open(const char *, int, int);
+extern MKMAP *mkmap_lmdb_open(const char *);
/*
* XXX Should be part of the DICT interface.
/* AUTHOR(S)
/* Howard Chu
/* Symas Corporation
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
/* void dict_close(dict)
/* DICT *dict;
/*
+/* typedef struct {
+/* .in +4
+/* char *type;
+/* DICT_OPEN_FN dict_fn;
+/* MKMAP_OPEN_FN mkmap_fn; /* See <mkmap.h> */
+/* .in -4
+/* } DICT_OPEN_INFO;
+/*
/* typedef DICT *(*DICT_OPEN_FN) (const char *, int, int);
/*
-/* dict_open_register(type, open)
-/* const char *type;
-/* DICT_OPEN_FN open;
+/* void dict_open_register(open_info)
+/* DICT_OPEN_INFO *open_info;
+/*
+/* const DICT_OPEN_INFO *dict_open_lookup(dict_type)
+/* const char *dict_type;
/*
-/* typedef DICT_OPEN_FN (*DICT_OPEN_EXTEND_FN)(const char *type);
+/* typedef DICT_OPEN_INFO (*DICT_OPEN_EXTEND_FN)(char *);
/*
/* DICT_OPEN_EXTEND_FN dict_open_extend(call_back)
/* DICT_OPEN_EXTEND_FN call_back;
/* associated data structures.
/*
/* dict_open_register() adds support for a new dictionary type.
+/* NOTE: this function does not copy its argument.
+/*
+/* dict_open_lookup() returns a pointer to the DICT_OPEN_INFO
+/* for the specified dictionary type, or a null pointer if the
+/* requested information is not found.
/*
/* dict_open_extend() registers a call-back function that looks
/* up the dictionary open() function for a type that is not
#include <split_at.h>
#include <htable.h>
#include <myflock.h>
+#include <mkmap.h>
/*
* lookup table for available map types.
*/
-typedef struct {
- char *type;
- DICT_OPEN_FN open;
-} DICT_OPEN_INFO;
-
static const DICT_OPEN_INFO dict_open_info[] = {
- DICT_TYPE_ENVIRON, dict_env_open,
- DICT_TYPE_HT, dict_ht_open,
- DICT_TYPE_UNIX, dict_unix_open,
- DICT_TYPE_TCP, dict_tcp_open,
+ DICT_TYPE_ENVIRON, dict_env_open, 0,
+ DICT_TYPE_HT, dict_ht_open, 0,
+ DICT_TYPE_UNIX, dict_unix_open, 0,
+ DICT_TYPE_TCP, dict_tcp_open, 0,
#ifdef HAS_DBM
- DICT_TYPE_DBM, dict_dbm_open,
+ DICT_TYPE_DBM, dict_dbm_open, mkmap_dbm_open,
#endif
#ifdef HAS_DB
- DICT_TYPE_HASH, dict_hash_open,
- DICT_TYPE_BTREE, dict_btree_open,
+ DICT_TYPE_HASH, dict_hash_open, mkmap_hash_open,
+ DICT_TYPE_BTREE, dict_btree_open, mkmap_btree_open,
#endif
#ifdef HAS_NIS
- DICT_TYPE_NIS, dict_nis_open,
+ DICT_TYPE_NIS, dict_nis_open, 0,
#endif
#ifdef HAS_NISPLUS
- DICT_TYPE_NISPLUS, dict_nisplus_open,
+ DICT_TYPE_NISPLUS, dict_nisplus_open, 0,
#endif
#ifdef HAS_NETINFO
- DICT_TYPE_NETINFO, dict_ni_open,
+ DICT_TYPE_NETINFO, dict_ni_open, 0,
#endif
#ifdef HAS_POSIX_REGEXP
- DICT_TYPE_REGEXP, dict_regexp_open,
+ DICT_TYPE_REGEXP, dict_regexp_open, 0,
#endif
- DICT_TYPE_STATIC, dict_static_open,
- DICT_TYPE_CIDR, dict_cidr_open,
- DICT_TYPE_THASH, dict_thash_open,
- DICT_TYPE_SOCKMAP, dict_sockmap_open,
- DICT_TYPE_FAIL, dict_fail_open,
- DICT_TYPE_PIPE, dict_pipe_open,
- DICT_TYPE_RANDOM, dict_random_open,
- DICT_TYPE_UNION, dict_union_open,
- DICT_TYPE_INLINE, dict_inline_open,
+ DICT_TYPE_STATIC, dict_static_open, 0,
+ DICT_TYPE_CIDR, dict_cidr_open, 0,
+ DICT_TYPE_THASH, dict_thash_open, 0,
+ DICT_TYPE_SOCKMAP, dict_sockmap_open, 0,
+ DICT_TYPE_FAIL, dict_fail_open, mkmap_fail_open,
+ DICT_TYPE_PIPE, dict_pipe_open, 0,
+ DICT_TYPE_RANDOM, dict_random_open, 0,
+ DICT_TYPE_UNION, dict_union_open, 0,
+ DICT_TYPE_INLINE, dict_inline_open, 0,
#ifndef USE_DYNAMIC_MAPS
#ifdef HAS_PCRE
- DICT_TYPE_PCRE, dict_pcre_open,
+ DICT_TYPE_PCRE, dict_pcre_open, 0,
#endif
#ifdef HAS_CDB
- DICT_TYPE_CDB, dict_cdb_open,
+ DICT_TYPE_CDB, dict_cdb_open, mkmap_cdb_open,
#endif
#ifdef HAS_SDBM
- DICT_TYPE_SDBM, dict_sdbm_open,
+ DICT_TYPE_SDBM, dict_sdbm_open, mkmap_sdbm_open,
#endif
#ifdef HAS_LMDB
- DICT_TYPE_LMDB, dict_lmdb_open,
+ DICT_TYPE_LMDB, dict_lmdb_open, mkmap_lmdb_open,
#endif
#endif /* !USE_DYNAMIC_MAPS */
0,
static DICT_MAPNAMES_EXTEND_FN dict_mapnames_extend_hook;
/*
- * Workaround.
+ * Workaround: define global variables here to control database cache sizes.
+ * When a database driver is dynamically loaded, global control variables
+ * cannot simply be owned by the loadable objects because that would result
+ * in build-time linker errors.
*/
DEFINE_DICT_LMDB_MAP_SIZE;
DEFINE_DICT_DB_CACHE_SIZE;
+ /*
+ * Replace obscure code with a more readable expression.
+ */
+#define NEED_DICT_OPEN_INIT() (dict_open_hash == 0)
+
/* dict_open_init - one-off initialization */
static void dict_open_init(void)
const char *myname = "dict_open_init";
const DICT_OPEN_INFO *dp;
- if (dict_open_hash != 0)
+ if (!NEED_DICT_OPEN_INIT())
msg_panic("%s: multiple initialization", myname);
dict_open_hash = htable_create(10);
return (dict);
}
-
/* dict_open3 - open dictionary */
DICT *dict_open3(const char *dict_type, const char *dict_name,
int open_flags, int dict_flags)
{
const char *myname = "dict_open";
- DICT_OPEN_INFO *dp;
- DICT_OPEN_FN open_fn;
+ const DICT_OPEN_INFO *dp;
DICT *dict;
if (*dict_type == 0 || *dict_name == 0)
msg_fatal("open dictionary: expecting \"type:name\" form instead of \"%s:%s\"",
dict_type, dict_name);
- if (dict_open_hash == 0)
+ if (NEED_DICT_OPEN_INIT())
dict_open_init();
- if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, 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,
+ if ((dp = dict_open_lookup(dict_type)) == 0)
+ return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
"unsupported dictionary type: %s", dict_type));
- }
- if ((dict = dp->open(dict_name, open_flags, dict_flags)) == 0)
+ if ((dict = dp->dict_fn(dict_name, open_flags, dict_flags)) == 0)
return (dict_surrogate(dict_type, dict_name, open_flags, dict_flags,
"cannot open %s:%s: %m", dict_type, dict_name));
if (msg_verbose)
/* dict_open_register - register dictionary type */
-void dict_open_register(const char *type, DICT_OPEN_FN open)
+void dict_open_register(const DICT_OPEN_INFO *dp)
{
const char *myname = "dict_open_register";
- DICT_OPEN_INFO *dp;
- HTABLE_INFO *ht;
- if (dict_open_hash == 0)
+ if (msg_verbose > 1)
+ msg_info("%s: %s", myname, dp->type);
+ if (NEED_DICT_OPEN_INIT())
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->open = open;
- ht = htable_enter(dict_open_hash, type, (void *) dp);
- dp->type = ht->key;
+ if (htable_find(dict_open_hash, dp->type))
+ msg_panic("%s: dictionary type exists: %s", myname, dp->type);
+ (void) htable_enter(dict_open_hash, dp->type, (void *) dp);
+}
+
+/* dict_open_lookup - look up DICT_OPEN_INFO for dictionary type */
+
+const DICT_OPEN_INFO *dict_open_lookup(const char *dict_type)
+{
+ const char myname[] = "dict_open_lookup";
+ const DICT_OPEN_INFO *dp;
+
+ if (msg_verbose > 1)
+ msg_info("%s: %s", myname, dict_type);
+ if ((dp = (DICT_OPEN_INFO *) htable_find(dict_open_hash, dict_type)) == 0
+ && dict_open_extend_hook != 0
+ && (dp = dict_open_extend_hook(dict_type)) != 0)
+ dict_open_register(dp);
+ return (dp);
}
/* dict_open_extend - register alternate dictionary search routine */
return (old_cb);
}
-/* dict_sort_alpha_cpp - qsort() callback */
-
-static int dict_sort_alpha_cpp(const void *a, const void *b)
-{
- return (strcmp(((char **) a)[0], ((char **) b)[0]));
-}
-
/* dict_mapnames - return an ARGV of available map_names */
ARGV *dict_mapnames()
DICT_OPEN_INFO *dp;
ARGV *mapnames;
- if (dict_open_hash == 0)
+ if (NEED_DICT_OPEN_INIT())
dict_open_init();
mapnames = argv_alloc(dict_open_hash->used + 1);
for (ht_info = ht = htable_list(dict_open_hash); *ht; ht++) {
}
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);
+ argv_qsort(mapnames, (ARGV_COMPAR_FN) 0);
+ /* In case some drivers have been loaded dynamically. */
+ argv_uniq(mapnames, (ARGV_COMPAR_FN) 0);
myfree((void *) ht_info);
argv_terminate(mapnames);
return mapnames;
* Utility library.
*/
#include <dict.h>
+#include <mkmap.h>
/*
* External interface.
#define DICT_TYPE_SDBM "sdbm"
extern DICT *dict_sdbm_open(const char *, int, int);
+extern MKMAP *mkmap_sdbm_open(const char *);
/* LICENSE
/* .ad
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
#endif
--- /dev/null
+#ifndef _MKMAP_H_INCLUDED_
+#define _MKMAP_H_INCLUDED_
+
+/*++
+/* NAME
+/* mkmap 3h
+/* SUMMARY
+/* create or rewrite Postfix database
+/* SYNOPSIS
+/* #include <mkmap.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * We try to open and lock a file before DB/DBM initialization. However, if
+ * the file does not exist then we may have to acquire the lock after the
+ * DB/DBM initialization.
+ */
+typedef struct MKMAP {
+ struct DICT *(*open) (const char *, int, int); /* 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 */
+} MKMAP;
+
+extern MKMAP *mkmap_open(const char *, const char *, int, int);
+extern void mkmap_close(MKMAP *);
+
+#define mkmap_append(map, key, val) dict_put((map)->dict, (key), (val))
+
+typedef MKMAP *(*MKMAP_OPEN_FN) (const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
+/*--*/
+
+#endif
/* SUMMARY
/* create or open database, CDB style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_cdb.h>
/*
/* MKMAP *mkmap_cdb_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
/* Utility library. */
#include <mymalloc.h>
-#include <dict.h>
-
-/* Application-specific. */
-
-#include "mkmap.h"
#include <dict_cdb.h>
/* This is a dummy module, since CDB has all the functionality
/* SUMMARY
/* create or open database, DB style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_db.h>
/*
/* MKMAP *mkmap_hash_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
-#include <dict.h>
#include <dict_db.h>
#include <myflock.h>
#include <warn_stat.h>
-/* Global library. */
-
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "mkmap.h"
-
#ifdef HAS_DB
#ifdef PATH_DB_H
#include PATH_DB_H
struct stat st;
/*
- * Override the default per-table cache size for map (re)builds.
- *
- * db_cache_size" is defined in util/dict_db.c and defaults to 128kB, which
- * works well for the lookup code.
- *
- * We use a larger per-table cache when building ".db" files. For "hash"
- * files performance degrades rapidly unless the memory pool is O(file
- * size).
- *
- * For "btree" files performance is good with sorted input even for small
- * memory pools, but with random input degrades rapidly unless the memory
- * pool is O(file size).
- *
- * XXX This should be specified via the DICT interface so that the buffer
- * size becomes an object property, instead of being specified by poking
- * a global variable so that it becomes a class property.
+ * Assumes that dict_db_cache_size = var_db_create_buf was done in the
+ * caller, because this code has no access to Postfix variables.
*/
- dict_db_cache_size = var_db_create_buf;
/*
* Fill in the generic members.
/* SUMMARY
/* create or open database, DBM style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_dbm.h>
/*
/* MKMAP *mkmap_dbm_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
-#include <dict.h>
#include <dict_dbm.h>
#include <myflock.h>
-/* Application-specific. */
-
-#include "mkmap.h"
-
#ifdef HAS_DBM
#ifdef PATH_NDBM_H
#include PATH_NDBM_H
/* SUMMARY
/* create or open database, fail: style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_fail.h>
/*
/* MKMAP *mkmap_fail_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
/* Utility library. */
#include <mymalloc.h>
-#include <dict.h>
-
-/* Application-specific. */
-
-#include <mkmap.h>
#include <dict_fail.h>
/*
/* SUMMARY
/* create or open database, LMDB style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_lmdb.h>
/*
/* MKMAP *mkmap_lmdb_open(path)
/* const char *path;
/* AUTHOR(S)
/* Howard Chu
/* Symas Corporation
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
/* Utility library. */
-#include <msg.h>
#include <mymalloc.h>
-#include <stringops.h>
-#include <dict.h>
#include <dict_lmdb.h>
-#include <myflock.h>
-#include <warn_stat.h>
+#include <mkmap.h>
#ifdef HAS_LMDB
#ifdef PATH_LMDB_H
#include <lmdb.h>
#endif
-/* Global library. */
-
-#include <mail_conf.h>
-#include <mail_params.h>
-
-/* Application-specific. */
-
-#include "mkmap.h"
-
/* mkmap_lmdb_open */
MKMAP *mkmap_lmdb_open(const char *path)
/* #include <mkmap.h>
/*
/* typedef struct MKMAP {
-/* DICT_OPEN_FN open; /* dict_xx_open() */
-/* DICT *dict; /* dict_xx_open() result */
+/* struct DICT *(*open) (const char *, int, int); /* 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 */
/*
/* 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
/*
/* 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
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
/* Utility library. */
#include <msg.h>
-#include <htable.h>
#include <dict.h>
-#include <dict_db.h>
-#include <dict_cdb.h>
-#include <dict_dbm.h>
-#include <dict_lmdb.h>
-#include <dict_sdbm.h>
-#include <dict_proxy.h>
-#include <dict_fail.h>
#include <sigdelay.h>
#include <mymalloc.h>
#include <stringops.h>
-
-/* Global library. */
-
-#include "mkmap.h"
-
- /*
- * Information about available database types. Here, we list only those map
- * types that support "bulk create" operations.
- *
- * 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_OPEN_FN before_open;
-} MKMAP_OPEN_INFO;
-
-static const MKMAP_OPEN_INFO mkmap_open_info[] = {
-#ifndef USE_DYNAMIC_MAPS
-#ifdef HAS_CDB
- DICT_TYPE_CDB, mkmap_cdb_open,
-#endif
-#ifdef HAS_SDBM
- DICT_TYPE_SDBM, mkmap_sdbm_open,
-#endif
-#ifdef HAS_LMDB
- DICT_TYPE_LMDB, mkmap_lmdb_open,
-#endif
-#endif /* !USE_DYNAMIC_MAPS */
-#ifdef HAS_DBM
- DICT_TYPE_DBM, mkmap_dbm_open,
-#endif
-#ifdef HAS_DB
- DICT_TYPE_HASH, mkmap_hash_open,
- DICT_TYPE_BTREE, mkmap_btree_open,
-#endif
- DICT_TYPE_FAIL, mkmap_fail_open,
- 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)
-{
- static 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, (void *) mp);
-}
-
-/* mkmap_open_register - register dictionary type */
-
-void mkmap_open_register(const char *type, MKMAP_OPEN_FN open_fn)
-{
- static 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, (void *) 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
-
-void mkmap_append(MKMAP *mkmap, const char *key, const char *value)
-{
- DICT *dict = mkmap->dict;
-
- if (dict_put(dict, key, value) != 0 && dict->error != 0)
- msg_fatal("%s:%s: update failed", dict->type, dict->name);
-}
+#include <mkmap.h>
/* mkmap_close - close database */
int open_flags, int dict_flags)
{
MKMAP *mkmap;
- const MKMAP_OPEN_INFO *mp;
- MKMAP_OPEN_FN open_fn;
+ const DICT_OPEN_INFO *dp;
/*
* Find out what map type to use.
*/
- 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 (mp == 0)
- msg_fatal("unsupported map type for this operation: %s", type);
- }
+ if ((dp = dict_open_lookup(type)) == 0)
+ msg_fatal("unsupported map type: %s", type);
+ if (dp->mkmap_fn == 0)
+ msg_fatal("no 'map create' support for this type: %s", type);
if (msg_verbose)
msg_info("open %s %s", type, path);
* dict modules implement locking only for individual record operations,
* because most Postfix applications don't need global exclusive locks.
*/
- mkmap = mp->before_open(path);
+ mkmap = dp->mkmap_fn(path);
/*
* Delay signal delivery, so that we won't leave the database in an
/* SUMMARY
/* create or open database, SDBM style
/* SYNOPSIS
-/* #include <mkmap.h>
+/* #include <dict_sdbm.h>
/*
/* MKMAP *mkmap_sdbm_open(path)
/* const char *path;
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Wietse Venema
+/* Google, Inc.
+/* 111 8th Avenue
+/* New York, NY 10011, USA
/*--*/
/* System library. */
#include <msg.h>
#include <mymalloc.h>
#include <stringops.h>
-#include <dict.h>
#include <dict_sdbm.h>
#include <myflock.h>
-/* Application-specific. */
-
-#include "mkmap.h"
-
#ifdef HAS_SDBM
#include <sdbm.h>