Hexadecimal encode/decode routines, from the TLS-enabled
version. Files: util/hext_code.[hc].
+20041212
+
+ Solaris 10/ix86 chroot setup script update by J.D. Bronson.
+
+20041213
+
+ Updated the SDBM dictionary interface. It had fallen behind
+ with the Postfix dictionary interfaces that were already
+ bundled with Postfix. Files: util/dict_sdbm.[hc].
+
+ Cleanup: "postconf -m" (show all available map types) now
+ produces sorted output. File: util/dict_open.c.
+
+20041215
+
+ No bugfix: tests with the new "postmap -s" feature show
+ that SDBM first/next operations never worked with Postfix/TLS
+ patch 20040829 (verified with the 20040829 dict_sdbm.c
+ module on Linux and FreeBSD). The code stops after finding
+ one database element. Other SDBM versions found on the
+ Internet will find all database entries, but report an I/O
+ error after the last database element is found. All this
+ would be easy enough to fix, but the SDBM library is not
+ part of Postfix, and never will be.
+
+ Bugfix: the sequence operator in the DBM and SDBM clients
+ released the shared lock after reading the next key but
+ before reading the corresponding value. This was never a
+ problem, because the sequence operator was used only in
+ the Postfix/TLS patch. This used the SDBM sequence operator
+ which didn't work as discussed above. Files: util/dict_dbm.c,
+ util/dict_sdbm.c.
+
Open problems:
Med: implement ${name[?:]value} in main.cf or update the
servers seem to need this in particular. Need a way to
expire cached results that are too old.
- Medium: make address rewriting on/off configurable for
- envelopes and/or headers.
-
Low: generic showq protocol, to allow for more intelligent
processing than just mailq. Maybe marry this with postsuper.
--- /dev/null
+#!/bin/sh
+# From original Solaris 8 version by Matthew X. Economou
+# Solaris 10 version updated by JD Bronson. Caution: this copies
+# too many files. There is no need to copy libc.so and other files
+# that are already linked in before a Postfix daemon chroots itself.
+
+COMMAND_DIRECTORY="/usr/sbin"
+DAEMON_DIRECTORY="/usr/libexec/postfix"
+QUEUE_DIRECTORY="/var/spool/postfix"
+
+## Copy any shared libraries, device entries, or configuration files
+## needed by Postfix into the jail.
+binlist="
+$DAEMON_DIRECTORY/virtual
+$DAEMON_DIRECTORY/trivial-rewrite
+$DAEMON_DIRECTORY/spawn
+$DAEMON_DIRECTORY/smtpd
+$DAEMON_DIRECTORY/smtp
+$DAEMON_DIRECTORY/showq
+$DAEMON_DIRECTORY/qmqpd
+$DAEMON_DIRECTORY/qmgr
+$DAEMON_DIRECTORY/proxymap
+$DAEMON_DIRECTORY/pipe
+$DAEMON_DIRECTORY/pickup
+$DAEMON_DIRECTORY/nqmgr
+$DAEMON_DIRECTORY/master
+$DAEMON_DIRECTORY/local
+$DAEMON_DIRECTORY/lmtp
+$DAEMON_DIRECTORY/flush
+$DAEMON_DIRECTORY/error
+$DAEMON_DIRECTORY/cleanup
+$DAEMON_DIRECTORY/bounce
+/usr/lib/sendmail
+$COMMAND_DIRECTORY/postsuper
+$COMMAND_DIRECTORY/postqueue
+$COMMAND_DIRECTORY/postmap
+$COMMAND_DIRECTORY/postlog
+$COMMAND_DIRECTORY/postlock
+$COMMAND_DIRECTORY/postkick
+$COMMAND_DIRECTORY/postfix
+$COMMAND_DIRECTORY/postdrop
+$COMMAND_DIRECTORY/postconf
+$COMMAND_DIRECTORY/postcat
+$COMMAND_DIRECTORY/postalias
+"
+ldd $binlist | awk '/[=]>/ { print $3 }' | sort -u | while read i
+do
+ mkdir -p $QUEUE_DIRECTORY`dirname $i`
+ ## Sun's version of tar sucks. We'll have to remove the leading
+ ## slashes from file names ourself, otherwise the copy doesn't
+ ## work.
+ (cd / && tar cphf - `echo $i | sed -e 's/^\///'`) | (cd $QUEUE_DIRECTORY && tar xpf -)
+done
+
+## More stuff for the jail, mostly discovered by inspection
+## (e.g. strings, lsof).
+more="
+/dev/zero
+/dev/null
+/dev/udp6
+/dev/tcp6
+/dev/udp
+/dev/tcp
+/dev/rawip
+/dev/ticlts
+/dev/ticotsord
+/dev/ticots
+/devices/pseudo/mm@0:zero
+/devices/pseudo/mm@0:null
+/devices/pseudo/udp6@0:udp6
+/devices/pseudo/tcp6@0:tcp6
+/devices/pseudo/udp@0:udp
+/devices/pseudo/tcp@0:tcp
+/devices/pseudo/icmp@0:icmp
+/devices/pseudo/tl@0:ticlts
+/devices/pseudo/tl@0:ticotsord
+/devices/pseudo/tl@0:ticots
+/etc/hosts
+/etc/nsswitch.conf
+/etc/netconfig
+/etc/passwd
+/etc/resolv.conf
+/etc/default/init
+/etc/default/nss
+/etc/inet/services
+/etc/inet/hosts
+/etc/services
+/lib/ld.so
+/lib/ld.so.1
+/usr/lib/nss_dns.so.1
+/usr/lib/sparcv9/straddr.so
+/usr/lib/straddr.so
+/usr/lib/straddr.so.2
+/lib/libintl.so
+/lib/libintl.so.1
+/lib/libw.so
+/lib/libw.so.1
+/lib/nss_nis.so.1
+/lib/nss_nisplus.so.1
+/lib/nss_dns.so.1
+/lib/nss_files.so.1
+/usr/share/lib/zoneinfo
+/var/ld/ld.config
+"
+for i in $more; do
+ mkdir -p $QUEUE_DIRECTORY`dirname $i`
+ (cd / && tar cpf - `echo $i | sed -e 's/^\///'`) | (cd $QUEUE_DIRECTORY && tar xpf -)
+done
+
+exit 0
The file format is described in <a href="regexp_table.5.html"><b>reg-</b></a>
<a href="regexp_table.5.html"><b>exp_table</b>(5)</a>.
+ <b>sdbm</b> An indexed file type based on hashing. This
+ is available only on systems with support
+ for SDBM databases.
+
<b>static</b> (read-only)
A table that always returns its name as
lookup result. For example, <b>static:foobar</b>
(default: empty)</b></DT><DD>
<p>
-If non-empty, filters the SMTP server's list of offered SASL mechanisms.
-Different client and server implementations may support different
-mechanism lists. By default, the client will use the intersection of the
-two. <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> further restricts what server mechanisms
-the client will take into consideration. </p>
+If non-empty, a Postfix SMTP client filter for the remote SMTP
+server's list of offered SASL mechanisms. Different client and
+server implementations may support different mechanism lists. By
+default, the Postfix SMTP client will use the intersection of the
+two. <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> further restricts what server
+mechanisms the client will take into consideration. </p>
<p> Specify mechanism names, "/file/name" patterns or "<a href="DATABASE_README.html">type:table</a>"
lookup tables. The right-hand side result from "<a href="DATABASE_README.html">type:table</a>" lookups
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> (empty)</b>
- If non-empty, filters the SMTP server's list of
- offered SASL mechanisms.
+ If non-empty, a Postfix SMTP client filter for the
+ remote SMTP server's list of offered SASL mecha-
+ nisms.
<b>RESOURCE AND RATE CONTROLS</b>
<b><a href="postconf.5.html#smtp_destination_concurrency_limit">smtp_destination_concurrency_limit</a> ($<a href="postconf.5.html#default_destination_concurrency_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_concurrency_limit">tion_concurrency_limit</a>)</b>
- The maximal number of parallel deliveries to the
- same destination via the smtp message delivery
+ The maximal number of parallel deliveries to the
+ same destination via the smtp message delivery
transport.
<b><a href="postconf.5.html#smtp_destination_recipient_limit">smtp_destination_recipient_limit</a> ($<a href="postconf.5.html#default_destination_recipient_limit">default_destina</a>-</b>
<b><a href="postconf.5.html#default_destination_recipient_limit">tion_recipient_limit</a>)</b>
- The maximal number of recipients per delivery via
+ The maximal number of recipients per delivery via
the smtp message delivery transport.
<b><a href="postconf.5.html#smtp_connect_timeout">smtp_connect_timeout</a> (30s)</b>
- The SMTP client time limit for completing a TCP
+ The SMTP client time limit for completing a TCP
connection, or zero (use the operating system
built-in time limit).
<b><a href="postconf.5.html#smtp_helo_timeout">smtp_helo_timeout</a> (300s)</b>
- The SMTP client time limit for sending the HELO or
- EHLO command, and for receiving the initial server
+ The SMTP client time limit for sending the HELO or
+ EHLO command, and for receiving the initial server
response.
<b><a href="postconf.5.html#smtp_xforward_timeout">smtp_xforward_timeout</a> (300s)</b>
command, and for receiving the server response.
<b><a href="postconf.5.html#smtp_mail_timeout">smtp_mail_timeout</a> (300s)</b>
- The SMTP client time limit for sending the MAIL
- FROM command, and for receiving the server
+ The SMTP client time limit for sending the MAIL
+ FROM command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_rcpt_timeout">smtp_rcpt_timeout</a> (300s)</b>
- The SMTP client time limit for sending the SMTP
- RCPT TO command, and for receiving the server
+ The SMTP client time limit for sending the SMTP
+ RCPT TO command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_data_init_timeout">smtp_data_init_timeout</a> (120s)</b>
- The SMTP client time limit for sending the SMTP
- DATA command, and for receiving the server
+ The SMTP client time limit for sending the SMTP
+ DATA command, and for receiving the server
response.
<b><a href="postconf.5.html#smtp_data_xfer_timeout">smtp_data_xfer_timeout</a> (180s)</b>
- The SMTP client time limit for sending the SMTP
+ The SMTP client time limit for sending the SMTP
message content.
<b><a href="postconf.5.html#smtp_data_done_timeout">smtp_data_done_timeout</a> (600s)</b>
- The SMTP client time limit for sending the SMTP
+ The SMTP client time limit for sending the SMTP
".", and for receiving the server response.
<b><a href="postconf.5.html#smtp_quit_timeout">smtp_quit_timeout</a> (300s)</b>
- The SMTP client time limit for sending the QUIT
+ The SMTP client time limit for sending the QUIT
command, and for receiving the server response.
Available in Postfix version 2.1 and later:
lookups, or zero (no limit).
<b><a href="postconf.5.html#smtp_mx_session_limit">smtp_mx_session_limit</a> (2)</b>
- The maximal number of SMTP sessions per delivery
- request before giving up or delivering to a fall-
+ The maximal number of SMTP sessions per delivery
+ request before giving up or delivering to a fall-
back relay host, or zero (no limit).
<b><a href="postconf.5.html#smtp_rset_timeout">smtp_rset_timeout</a> (20s)</b>
- The SMTP client time limit for sending the RSET
+ The SMTP client time limit for sending the RSET
command, and for receiving the server response.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
- Permanently enable SMTP connection caching for the
+ Permanently enable SMTP connection caching for the
specified destinations.
<b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
- Temporarily enable SMTP connection caching while a
+ Temporarily enable SMTP connection caching while a
destination has a high volume of mail in the active
queue.
<b><a href="postconf.5.html#smtp_connection_cache_reuse_limit">smtp_connection_cache_reuse_limit</a> (10)</b>
When SMTP connection caching is enabled, the number
- of times that an SMTP session is reused before it
+ of times that an SMTP session is reused before it
is closed.
<b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
When SMTP connection caching is enabled, the amount
- of time that an unused SMTP client socket is kept
+ of time that an unused SMTP client socket is kept
open before it is closed.
<b>TROUBLE SHOOTING CONTROLS</b>
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- The increment in verbose logging level when a
- remote client or server matches a pattern in the
+ The increment in verbose logging level when a
+ remote client or server matches a pattern in the
<a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- Optional list of remote client or server hostname
- or network address patterns that cause the verbose
- logging level to increase by the amount specified
+ Optional list of remote client or server hostname
+ or network address patterns that cause the verbose
+ logging level to increase by the amount specified
in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
<b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
- The recipient of postmaster notifications about
- mail delivery problems that are caused by policy,
+ The recipient of postmaster notifications about
+ mail delivery problems that are caused by policy,
resource, software or protocol errors.
<b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
- The list of error classes that are reported to the
+ The list of error classes that are reported to the
postmaster.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
- Where the Postfix SMTP client should deliver mail
+ Where the Postfix SMTP client should deliver mail
when it detects a "mail loops back to myself" error
condition.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
- Disable DNS lookups in the Postfix SMTP and LMTP
+ Disable DNS lookups in the Postfix SMTP and LMTP
clients.
<b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
- Optional list of relay hosts for SMTP destinations
+ Optional list of relay hosts for SMTP destinations
that can't be found or that are unreachable.
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
over an internal communication channel.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon pro-
+ The process ID of a Postfix command or daemon pro-
cess.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
The network interface addresses that this mail sys-
- tem receives mail on by way of a proxy or network
+ tem receives mail on by way of a proxy or network
address translation unit.
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
client should bind to when making a connection.
<b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- The hostname to send in the SMTP EHLO or HELO com-
+ The hostname to send in the SMTP EHLO or HELO com-
mand.
<b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
- What mechanisms when the SMTP client uses to look
+ What mechanisms when the SMTP client uses to look
up a host's IP address.
<b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
- Randomize the order of equal-preference MX host
+ Randomize the order of equal-preference MX host
addresses.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the pro-
+ The mail system name that is prepended to the pro-
cess name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
<a href="SASL_README.html">SASL_README</a>, Postfix SASL howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
.IP "\fBregexp\fR (read-only)"
A lookup table based on regular expressions. The file format is
described in \fBregexp_table\fR(5).
+.IP \fBsdbm\fR
+An indexed file type based on hashing.
+This is available only on systems with support for SDBM databases.
.IP "\fBstatic\fR (read-only)"
A table that always returns its name as lookup result. For example,
\fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
.ad
.ft R
.SH smtp_sasl_mechanism_filter (default: empty)
-If non-empty, filters the SMTP server's list of offered SASL mechanisms.
-Different client and server implementations may support different
-mechanism lists. By default, the client will use the intersection of the
-two. smtp_sasl_mechanism_filter further restricts what server mechanisms
-the client will take into consideration.
+If non-empty, a Postfix SMTP client filter for the remote SMTP
+server's list of offered SASL mechanisms. Different client and
+server implementations may support different mechanism lists. By
+default, the Postfix SMTP client will use the intersection of the
+two. smtp_sasl_mechanism_filter further restricts what server
+mechanisms the client will take into consideration.
.PP
Specify mechanism names, "/file/name" patterns or "type:table"
lookup tables. The right-hand side result from "type:table" lookups
.PP
Available in Postfix version 2.2 and later:
.IP "\fBsmtp_sasl_mechanism_filter (empty)\fR"
-If non-empty, filters the SMTP server's list of offered SASL mechanisms.
+If non-empty, a Postfix SMTP client filter for the remote SMTP
+server's list of offered SASL mechanisms.
.SH "RESOURCE AND RATE CONTROLS"
.na
.nf
%PARAM smtp_sasl_mechanism_filter
<p>
-If non-empty, filters the SMTP server's list of offered SASL mechanisms.
-Different client and server implementations may support different
-mechanism lists. By default, the client will use the intersection of the
-two. smtp_sasl_mechanism_filter further restricts what server mechanisms
-the client will take into consideration. </p>
+If non-empty, a Postfix SMTP client filter for the remote SMTP
+server's list of offered SASL mechanisms. Different client and
+server implementations may support different mechanism lists. By
+default, the Postfix SMTP client will use the intersection of the
+two. smtp_sasl_mechanism_filter further restricts what server
+mechanisms the client will take into consideration. </p>
<p> Specify mechanism names, "/file/name" patterns or "type:table"
lookup tables. The right-hand side result from "type:table" lookups
mkmap_open.o: ../../include/dict_db.h
mkmap_open.o: ../../include/dict_cdb.h
mkmap_open.o: ../../include/dict_dbm.h
+mkmap_open.o: ../../include/dict_sdbm.h
mkmap_open.o: ../../include/sigdelay.h
mkmap_open.o: ../../include/mymalloc.h
mkmap_open.o: mkmap.h
* Patches change the patchlevel and the release date. Snapshots change the
* release date only.
*/
-#define MAIL_RELEASE_DATE "20041211"
+#define MAIL_RELEASE_DATE "20041215"
#define MAIL_VERSION_NUMBER "2.2"
#define VAR_MAIL_VERSION "mail_version"
extern MKMAP *mkmap_cdb_open(const char *);
extern MKMAP *mkmap_hash_open(const char *);
extern MKMAP *mkmap_btree_open(const char *);
+extern MKMAP *mkmap_sdbm_open(const char *);
/* LICENSE
/* .ad
#include <dict_db.h>
#include <dict_cdb.h>
#include <dict_dbm.h>
+#include <dict_sdbm.h>
#include <sigdelay.h>
#include <mymalloc.h>
/* .IP "\fBregexp\fR (read-only)"
/* A lookup table based on regular expressions. The file format is
/* described in \fBregexp_table\fR(5).
+/* .IP \fBsdbm\fR
+/* An indexed file type based on hashing.
+/* This is available only on systems with support for SDBM databases.
/* .IP "\fBstatic\fR (read-only)"
/* A table that always returns its name as lookup result. For example,
/* \fBstatic:foobar\fR always returns the string \fBfoobar\fR as lookup
/* .PP
/* Available in Postfix version 2.2 and later:
/* .IP "\fBsmtp_sasl_mechanism_filter (empty)\fR"
-/* If non-empty, filters the SMTP server's list of offered SASL mechanisms.
+/* If non-empty, a Postfix SMTP client filter for the remote SMTP
+/* server's list of offered SASL mechanisms.
/* RESOURCE AND RATE CONTROLS
/* .ad
/* .fi
DICT_DBM *dict_dbm = (DICT_DBM *) dict;
datum dbm_key;
int status = 1;
- int flags = 0;
/*
* Sanity check.
DICT_DBM *dict_dbm = (DICT_DBM *) dict;
datum dbm_key;
datum dbm_value;
- int status = 0;
/*
* Acquire a shared lock.
msg_panic("%s: invalid function: %d", myname, function);
}
- /*
- * Release the shared lock.
- */
- if ((dict->flags & DICT_FLAG_LOCK)
- && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
-
if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
/*
msg_fatal("error seeking %s: %m", dict_dbm->dict.name);
return (1); /* no error: eof/not found */
}
+
+ /*
+ * Release the shared lock.
+ */
+ if ((dict->flags & DICT_FLAG_LOCK)
+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+ msg_fatal("%s: unlock dictionary: %m", dict_dbm->dict.name);
+
return (0);
}
/* dict_open_register(type, open)
/* char *type;
/* DICT *(*open) (const char *, int, int);
+/*
+/* ARGV *dict_mapnames()
/* DESCRIPTION
/* This module implements a low-level interface to multiple
/* physical dictionary types.
/* associated data structures.
/*
/* dict_open_register() adds support for a new dictionary type.
+/*
+/* dict_mapnames() returns a sorted list with the names of all available
+/* dictionary types.
/* DIAGNOSTICS
/* Fatal error: open error, unsupported dictionary type, attempt to
/* update non-writable dictionary.
#include <sys_defs.h>
#include <string.h>
+#include <stdlib.h>
#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
htable_enter(dict_open_hash, dp->type, (char *) dp);
}
+/* 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()
dp = (DICT_OPEN_INFO *) ht[0]->value;
argv_add(mapnames, dp->type, ARGV_END);
}
+ qsort((void *) mapnames->argv, mapnames->argc, sizeof(mapnames->argv[0]),
+ dict_sort_alpha_cpp);
myfree((char *) ht_info);
argv_terminate(mapnames);
return mapnames;
typedef struct {
DICT dict; /* generic members */
SDBM *dbm; /* open database */
- char *path; /* pathname */
+ VSTRING *key_buf; /* key buffer */
+ VSTRING *val_buf; /* result buffer */
} DICT_SDBM;
+#define SCOPY(buf, data, size) \
+ vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
+
/* dict_sdbm_lookup - find database entry */
static const char *dict_sdbm_lookup(DICT *dict, const char *name)
DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
datum dbm_key;
datum dbm_value;
- static VSTRING *buf;
const char *result = 0;
+ /*
+ * Sanity check.
+ */
+ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ msg_panic("dict_sdbm_lookup: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+
dict_errno = 0;
/*
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name);
/*
* See if this DBM file was written with one null byte appended to key
dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
if (dbm_value.dptr != 0) {
dict->flags &= ~DICT_FLAG_TRY0NULL;
- result = dbm_value.dptr;
+ result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
}
}
dbm_key.dsize = strlen(name);
dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
if (dbm_value.dptr != 0) {
- if (buf == 0)
- buf = vstring_alloc(10);
- vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
dict->flags &= ~DICT_FLAG_TRY1NULL;
- result = vstring_str(buf);
+ result = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
}
}
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
return (result);
}
datum dbm_value;
int status;
+ /*
+ * Sanity check.
+ */
+ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ msg_panic("dict_sdbm_update: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
+
dbm_key.dptr = (void *) name;
dbm_value.dptr = (void *) value;
dbm_key.dsize = strlen(name);
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name);
/*
* Do the update.
*/
if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value,
(dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0)
- msg_fatal("error writing SDBM database %s: %m", dict_sdbm->path);
+ msg_fatal("error writing SDBM database %s: %m", dict_sdbm->dict.name);
if (status) {
if (dict->flags & DICT_FLAG_DUP_IGNORE)
/* void */ ;
else if (dict->flags & DICT_FLAG_DUP_WARN)
- msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
+ msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name);
else
- msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
+ msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->dict.name, name);
}
/*
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
}
-
/* dict_sdbm_delete - delete one entry from the dictionary */
static int dict_sdbm_delete(DICT *dict, const char *name)
DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
datum dbm_key;
int status = 1;
- int flags = 0;
+
+ /*
+ * Sanity check.
+ */
+ if ((dict->flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
+ msg_panic("dict_sdbm_delete: no DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL flag");
/*
* Acquire an exclusive lock.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name);
/*
* See if this DBM file was written with one null byte appended to key
dbm_key.dsize = strlen(name) + 1;
sdbm_clearerr(dict_sdbm->dbm);
if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
- if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */
- msg_fatal("error deleting from %s: %m", dict_sdbm->path);
+ if (sdbm_error(dict_sdbm->dbm) != 0)/* fatal error */
+ msg_fatal("error deleting from %s: %m", dict_sdbm->dict.name);
status = 1; /* not found */
} else {
dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */
dbm_key.dsize = strlen(name);
sdbm_clearerr(dict_sdbm->dbm);
if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
- if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */
- msg_fatal("error deleting from %s: %m", dict_sdbm->path);
+ if (sdbm_error(dict_sdbm->dbm) != 0)/* fatal error */
+ msg_fatal("error deleting from %s: %m", dict_sdbm->dict.name);
status = 1; /* not found */
} else {
dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
return (status);
}
/* traverse the dictionary */
static int dict_sdbm_sequence(DICT *dict, const int function,
- const char **key, const char **value)
+ const char **key, const char **value)
{
char *myname = "dict_sdbm_sequence";
DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
datum dbm_key;
datum dbm_value;
- int status = 0;
- static VSTRING *key_buf;
- static VSTRING *value_buf;
/*
* Acquire a shared lock.
*/
if ((dict->flags & DICT_FLAG_LOCK)
&& myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
- msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->dict.name);
/*
* Determine and execute the seek function. It returns the key.
*/
+ sdbm_clearerr(dict_sdbm->dbm);
switch (function) {
case DICT_SEQ_FUN_FIRST:
dbm_key = sdbm_firstkey(dict_sdbm->dbm);
msg_panic("%s: invalid function: %d", myname, function);
}
- /*
- * Release the shared lock.
- */
- if ((dict->flags & DICT_FLAG_LOCK)
- && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
- msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
-
if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
/*
- * See if this DB file was written with one null byte appended to key
- * and value or not. If necessary, copy the key.
+ * Copy the key so that it is guaranteed null terminated.
*/
- if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) {
- *key = dbm_key.dptr;
- } else {
- if (key_buf == 0)
- key_buf = vstring_alloc(10);
- vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize);
- *key = vstring_str(key_buf);
- }
+ *key = SCOPY(dict_sdbm->key_buf, dbm_key.dptr, dbm_key.dsize);
/*
* Fetch the corresponding value.
if (dbm_value.dptr != 0 && dbm_value.dsize > 0) {
/*
- * See if this DB file was written with one null byte appended to
- * key and value or not. If necessary, copy the key.
+ * Copy the value so that it is guaranteed null terminated.
*/
- if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) {
- *value = dbm_value.dptr;
- } else {
- if (value_buf == 0)
- value_buf = vstring_alloc(10);
- vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize);
- *value = vstring_str(value_buf);
- }
+ *value = SCOPY(dict_sdbm->val_buf, dbm_value.dptr, dbm_value.dsize);
} else {
/*
* condition.
*/
if (sdbm_error(dict_sdbm->dbm))
- msg_fatal("error seeking %s: %m", dict_sdbm->path);
+ msg_fatal("error seeking %s: %m", dict_sdbm->dict.name);
return (1); /* no error: eof/not found
* (should not happen!) */
}
* Determine if we have hit the last record or an error condition.
*/
if (sdbm_error(dict_sdbm->dbm))
- msg_fatal("error seeking %s: %m", dict_sdbm->path);
+ msg_fatal("error seeking %s: %m", dict_sdbm->dict.name);
return (1); /* no error: eof/not found */
}
+
+ /*
+ * Release the shared lock.
+ */
+ if ((dict->flags & DICT_FLAG_LOCK)
+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->dict.name);
+
return (0);
}
DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
sdbm_close(dict_sdbm->dbm);
- myfree(dict_sdbm->path);
- myfree((char *) dict_sdbm);
+ if (dict_sdbm->key_buf)
+ vstring_free(dict_sdbm->key_buf);
+ if (dict_sdbm->val_buf)
+ vstring_free(dict_sdbm->val_buf);
+ dict_free(dict);
}
/* dict_sdbm_open - open SDBM data base */
char *dbm_path;
int lock_fd;
+ /*
+ * Note: DICT_FLAG_LOCK is used only by programs that do fine-grained (in
+ * the time domain) locking while accessing individual database records.
+ *
+ * Programs such as postmap/postalias use their own large-grained (in the
+ * time domain) locks while rewriting the entire file.
+ */
if (dict_flags & DICT_FLAG_LOCK) {
- dbm_path = concatenate(path, ".pag", (char *) 0);
+ dbm_path = concatenate(path, ".dir", (char *) 0);
if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0)
msg_fatal("open database %s: %m", dbm_path);
if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
msg_fatal("unlock database %s for open: %m", dbm_path);
if (close(lock_fd) < 0)
msg_fatal("close database %s: %m", dbm_path);
- myfree(dbm_path);
}
- dict_sdbm = (DICT_SDBM *) mymalloc(sizeof(*dict_sdbm));
+ dict_sdbm = (DICT_SDBM *) dict_alloc(DICT_TYPE_SDBM, path, sizeof(*dict_sdbm));
dict_sdbm->dict.lookup = dict_sdbm_lookup;
dict_sdbm->dict.update = dict_sdbm_update;
dict_sdbm->dict.delete = dict_sdbm_delete;
if (fstat(dict_sdbm->dict.stat_fd, &st) < 0)
msg_fatal("dict_sdbm_open: fstat: %m");
dict_sdbm->dict.mtime = st.st_mtime;
+
+ /*
+ * Warn if the source file is newer than the indexed file, except when
+ * the source file changed only seconds ago.
+ */
+ if ((dict_flags & DICT_FLAG_LOCK) != 0
+ && stat(path, &st) == 0
+ && st.st_mtime > dict_sdbm->dict.mtime
+ && st.st_mtime < time((time_t *) 0) - 100)
+ msg_warn("database %s is older than source file %s", dbm_path, path);
+
close_on_exec(sdbm_pagfno(dbm), CLOSE_ON_EXEC);
close_on_exec(sdbm_dirfno(dbm), CLOSE_ON_EXEC);
dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
dict_sdbm->dbm = dbm;
- dict_sdbm->path = mystrdup(path);
+ dict_sdbm->key_buf = 0;
+ dict_sdbm->val_buf = 0;
+
+ if ((dict_flags & DICT_FLAG_LOCK))
+ myfree(dbm_path);
- return (&dict_sdbm->dict);
+ return (DICT_DEBUG (&dict_sdbm->dict));
}
#endif