This reuses the existing proxy object created by the dict_debug()
function.
---
proto/DATABASE_README.html | 13 +++++++
src/postconf/Makefile.in | 1 +
src/postconf/postconf.c | 10 +++++
src/postconf/postconf_dbms.c | 12 ++++--
src/postconf/test28-main.cf | 12 ++++++
src/postconf/test28.ref | 12 ++++--
src/postconf/test29-main.cf | 54 ++++++++++++++++++++++++++
src/postconf/test29.ref | 60 +++++++++++++++++++++++------
src/proxymap/Makefile.in | 1 +
src/proxymap/proxymap.c | 2 +
src/util/Makefile.in | 12 +++++-
src/util/dict_debug.c | 73 +++++++++++++++++++++++++++++++++---
src/util/dict_debug.h | 34 +++++++++++++++++
src/util/dict_debug_test.ref | 51 +++++++++++++++++++++++++
src/util/dict_debug_test.sh | 25 ++++++++++++
src/util/dict_open.c | 2 +
16 files changed, 348 insertions(+), 26 deletions(-)
create mode 100644 src/util/dict_debug.h
create mode 100644 src/util/dict_debug_test.ref
create mode 100755 src/util/dict_debug_test.sh
diff --git a/proto/DATABASE_README.html b/proto/DATABASE_README.html
index 42a54ac7c..4182bb8c8 100644
--- a/proto/DATABASE_README.html
+++ b/proto/DATABASE_README.html
@@ -293,6 +293,19 @@ databases are maintained by Postfix daemons. The lookup
table name
as used in "dbm:table" is the database file name without the ".dir"
or ".pag" suffix. </dd>
+<dt> <b>debug</b> </dt>
+
+<dd>
+<p> An adapter for another table that causes all accesses to be
+logged. Example usage: "debug:hash:/etc/postfix/example". The
+formats of the log messages are unspecified and subject to change.
+Warning: If a query or the underlying table contains sensitive
+information (such as a password), that information might be
+logged. </p>
+
+<p> This feature is available with Postfix 3.11 and later. </p>
+</dd>
+
<dt> <b>environ</b> </dt>
<dd> The UNIX process environment array. The lookup key is the
diff --git a/src/postconf/Makefile.in b/src/postconf/Makefile.in
index e23a81f87..a3c22b14b 100644
--- a/src/postconf/Makefile.in
+++ b/src/postconf/Makefile.in
@@ -1129,6 +1129,7 @@ postconf_builtin.o: time_vars.h
postconf_dbms.o: ../../include/argv.h
postconf_dbms.o: ../../include/check_arg.h
postconf_dbms.o: ../../include/dict.h
+postconf_dbms.o: ../../include/dict_debug.h
postconf_dbms.o: ../../include/dict_ht.h
postconf_dbms.o: ../../include/dict_ldap.h
postconf_dbms.o: ../../include/dict_memcache.h
diff --git a/src/postconf/postconf.c b/src/postconf/postconf.c
index 74f13b2cd..402c96d7f 100644
--- a/src/postconf/postconf.c
+++ b/src/postconf/postconf.c
@@ -252,6 +252,16 @@
/* .IP \fBdbm\fR
/* An indexed file type based on hashing. Available on systems
/* with support for DBM databases.
+/* .IP \fBdebug\fR
+/* An adapter for another table that causes all accesses to be
+/* logged. The table name syntax is \fItype\fB:\fIname\fR.
+/* Example usage: \fBdebug:hash:/etc/postfix/example\fR. The
+/* formats of the log messages are unspecified and subject to
+/* change. Warning: If a query or the underlying table contains
+/* sensitive information (such as a password), that information
+/* might be logged.
+/*
+/* This feature is available with Postfix 3.11 and later.
/* .IP \fBenviron\fR
/* The UNIX process environment array. The lookup key is the
/* environment variable name; the table name is ignored. Originally
diff --git a/src/postconf/postconf_dbms.c b/src/postconf/postconf_dbms.c
index 105ae85ea..0b0fb9610 100644
--- a/src/postconf/postconf_dbms.c
+++ b/src/postconf/postconf_dbms.c
@@ -74,6 +74,7 @@
#include <mail_conf.h>
#include <mail_params.h>
+#include <dict_debug.h>
#include <dict_ht.h>
#include <dict_proxy.h>
#include <dict_ldap.h>
@@ -280,11 +281,16 @@ static void pcf_register_dbms_helper(int mode, char
*str_value,
}
/*
- * Skip over "proxy:" maptypes, to emulate the proxymap(8) server's
- * behavior when opening a local database configuration file.
+ * Skip over adapter maptypes "proxy:" and "debug:", to emulate their
+ * behavior when wrapping a local database configuration file.
+ *
+ * TODO(rhansen): What about database table specs embedded inside the
+ * names for "pipemap:" and "unionmap:" tables? Does anything need to
+ * be done here for those?
*/
while ((prefix = split_at(db_type, ':')) != 0
- && strcmp(db_type, DICT_TYPE_PROXY) == 0)
+ && (strcmp(db_type, DICT_TYPE_PROXY) == 0 ||
+ strcmp(db_type, DICT_TYPE_DEBUG) == 0))
db_type = prefix;
if (prefix == 0)
diff --git a/src/postconf/test28-main.cf b/src/postconf/test28-main.cf
index 6f33bc398..2182b66be 100644
--- a/src/postconf/test28-main.cf
+++ b/src/postconf/test28-main.cf
@@ -1,15 +1,27 @@
_unused_tables =
ldap:_unused_ldap
+ debug:ldap:_unused_debug_ldap
proxy:ldap:_unused_proxy_ldap
+ debug:proxy:ldap:_unused_debug_proxy_ldap
+ proxy:debug:ldap:_unused_proxy_debug_ldap
_unused_ldap_domain = whatever
+_unused_debug_ldap_domain = whatever
_unused_proxy_ldap_domain = whatever
+_unused_debug_proxy_ldap_domain = whatever
+_unused_proxy_debug_ldap_domain = whatever
header_checks = $_used_tables
_used_tables =
ldap:_used_ldap
+ debug:ldap:_used_debug_ldap
proxy:ldap:_used_proxy_ldap
+ debug:proxy:ldap:_used_debug_proxy_ldap
+ proxy:debug:ldap:_used_proxy_debug_ldap
_used_ldap_domain = whatever
+_used_debug_ldap_domain = whatever
_used_proxy_ldap_domain = whatever
+_used_debug_proxy_ldap_domain = whatever
+_used_proxy_debug_ldap_domain = whatever
# These are referenced by master.cf ($aap_domain is referenced indirectly via
# the memcache:aap table specified as $db:$zz in master.cf).
diff --git a/src/postconf/test28.ref b/src/postconf/test28.ref
index fdd723188..7fe9a3466 100644
--- a/src/postconf/test28.ref
+++ b/src/postconf/test28.ref
@@ -1,6 +1,9 @@
+_used_debug_ldap_domain = whatever
+_used_debug_proxy_ldap_domain = whatever
_used_ldap_domain = whatever
+_used_proxy_debug_ldap_domain = whatever
_used_proxy_ldap_domain = whatever
-_used_tables = ldap:_used_ldap proxy:ldap:_used_proxy_ldap
+_used_tables = ldap:_used_ldap debug:ldap:_used_debug_ldap
proxy:ldap:_used_proxy_ldap debug:proxy:ldap:_used_debug_proxy_ldap
proxy:debug:ldap:_used_proxy_debug_ldap
aap_domain = whatever
config_directory = .
db = memcache
@@ -8,6 +11,9 @@ header_checks = $_used_tables
yy = aap
zz = $yy
./postconf: warning: ./main.cf: unused parameter: _unused_ldap_domain=whatever
-./postconf: warning: ./main.cf: unused parameter:
_unused_proxy_ldap_domain=whatever
-./postconf: warning: ./main.cf: unused parameter:
_unused_tables=ldap:_unused_ldap proxy:ldap:_unused_proxy_ldap
./postconf: warning: ./main.cf: unused parameter: aa_domain=whatever
+./postconf: warning: ./main.cf: unused parameter:
_unused_tables=ldap:_unused_ldap debug:ldap:_unused_debug_ldap
proxy:ldap:_unused_proxy_ldap debug:proxy:ldap:_unused_debug_proxy_ldap
proxy:debug:ldap:_unused_proxy_debug_ldap
+./postconf: warning: ./main.cf: unused parameter:
_unused_proxy_ldap_domain=whatever
+./postconf: warning: ./main.cf: unused parameter:
_unused_proxy_debug_ldap_domain=whatever
+./postconf: warning: ./main.cf: unused parameter:
_unused_debug_proxy_ldap_domain=whatever
+./postconf: warning: ./main.cf: unused parameter:
_unused_debug_ldap_domain=whatever
diff --git a/src/postconf/test29-main.cf b/src/postconf/test29-main.cf
index 9fc223748..c114d3e09 100644
--- a/src/postconf/test29-main.cf
+++ b/src/postconf/test29-main.cf
@@ -1,50 +1,104 @@
_ldap_tables =
ldap:_ldap
+ debug:ldap:_debug_ldap
proxy:ldap:_proxy_ldap
+ debug:proxy:ldap:_debug_proxy_ldap
+ proxy:debug:ldap:_proxy_debug_ldap
_ldap_domain = whatever
_ldap_domainx = whatever
+_debug_ldap_domain = whatever
+_debug_ldap_domainx = whatever
_proxy_ldap_domain = whatever
_proxy_ldap_domainx = whatever
+_debug_proxy_ldap_domain = whatever
+_debug_proxy_ldap_domainx = whatever
+_proxy_debug_ldap_domain = whatever
+_proxy_debug_ldap_domainx = whatever
_memcache_tables =
memcache:_memcache
+ debug:memcache:_debug_memcache
proxy:memcache:_proxy_memcache
+ debug:proxy:memcache:_debug_proxy_memcache
+ proxy:debug:memcache:_proxy_debug_memcache
_memcache_domain = whatever
_memcache_domainx = whatever
+_debug_memcache_domain = whatever
+_debug_memcache_domainx = whatever
_proxy_memcache_domain = whatever
_proxy_memcache_domainx = whatever
+_debug_proxy_memcache_domain = whatever
+_debug_proxy_memcache_domainx = whatever
+_proxy_debug_memcache_domain = whatever
+_proxy_debug_memcache_domainx = whatever
_mongodb_tables =
mongodb:_mongodb
+ debug:mongodb:_debug_mongodb
proxy:mongodb:_proxy_mongodb
+ debug:proxy:mongodb:_debug_proxy_mongodb
+ proxy:debug:mongodb:_proxy_debug_mongodb
_mongodb_domain = whatever
_mongodb_domainx = whatever
+_debug_mongodb_domain = whatever
+_debug_mongodb_domainx = whatever
_proxy_mongodb_domain = whatever
_proxy_mongodb_domainx = whatever
+_debug_proxy_mongodb_domain = whatever
+_debug_proxy_mongodb_domainx = whatever
+_proxy_debug_mongodb_domain = whatever
+_proxy_debug_mongodb_domainx = whatever
_mysql_tables =
mysql:_mysql
+ debug:mysql:_debug_mysql
proxy:mysql:_proxy_mysql
+ debug:proxy:mysql:_debug_proxy_mysql
+ proxy:debug:mysql:_proxy_debug_mysql
_mysql_domain = whatever
_mysql_domainx = whatever
+_debug_mysql_domain = whatever
+_debug_mysql_domainx = whatever
_proxy_mysql_domain = whatever
_proxy_mysql_domainx = whatever
+_debug_proxy_mysql_domain = whatever
+_debug_proxy_mysql_domainx = whatever
+_proxy_debug_mysql_domain = whatever
+_proxy_debug_mysql_domainx = whatever
_pgsql_tables =
pgsql:_pgsql
+ debug:pgsql:_debug_pgsql
proxy:pgsql:_proxy_pgsql
+ debug:proxy:pgsql:_debug_proxy_pgsql
+ proxy:debug:pgsql:_proxy_debug_pgsql
_pgsql_domain = whatever
_pgsql_domainx = whatever
+_debug_pgsql_domain = whatever
+_debug_pgsql_domainx = whatever
_proxy_pgsql_domain = whatever
_proxy_pgsql_domainx = whatever
+_debug_proxy_pgsql_domain = whatever
+_debug_proxy_pgsql_domainx = whatever
+_proxy_debug_pgsql_domain = whatever
+_proxy_debug_pgsql_domainx = whatever
_sqlite_tables =
sqlite:_sqlite
+ debug:sqlite:_debug_sqlite
proxy:sqlite:_proxy_sqlite
+ debug:proxy:sqlite:_debug_proxy_sqlite
+ proxy:debug:sqlite:_proxy_debug_sqlite
_sqlite_domain = whatever
_sqlite_domainx = whatever
+_debug_sqlite_domain = whatever
+_debug_sqlite_domainx = whatever
_proxy_sqlite_domain = whatever
_proxy_sqlite_domainx = whatever
+_debug_proxy_sqlite_domain = whatever
+_debug_proxy_sqlite_domainx = whatever
+_proxy_debug_sqlite_domain = whatever
+_proxy_debug_sqlite_domainx = whatever
header_checks =
$_ldap_tables
diff --git a/src/postconf/test29.ref b/src/postconf/test29.ref
index b188d5215..9acc6e212 100644
--- a/src/postconf/test29.ref
+++ b/src/postconf/test29.ref
@@ -1,13 +1,31 @@
+_debug_ldap_domain = whatever
+_debug_memcache_domain = whatever
+_debug_mongodb_domain = whatever
+_debug_mysql_domain = whatever
+_debug_pgsql_domain = whatever
+_debug_proxy_ldap_domain = whatever
+_debug_proxy_memcache_domain = whatever
+_debug_proxy_mongodb_domain = whatever
+_debug_proxy_mysql_domain = whatever
+_debug_proxy_pgsql_domain = whatever
+_debug_proxy_sqlite_domain = whatever
+_debug_sqlite_domain = whatever
_ldap_domain = whatever
-_ldap_tables = ldap:_ldap proxy:ldap:_proxy_ldap
+_ldap_tables = ldap:_ldap debug:ldap:_debug_ldap proxy:ldap:_proxy_ldap
debug:proxy:ldap:_debug_proxy_ldap proxy:debug:ldap:_proxy_debug_ldap
_memcache_domain = whatever
-_memcache_tables = memcache:_memcache proxy:memcache:_proxy_memcache
+_memcache_tables = memcache:_memcache debug:memcache:_debug_memcache
proxy:memcache:_proxy_memcache debug:proxy:memcache:_debug_proxy_memcache
proxy:debug:memcache:_proxy_debug_memcache
_mongodb_domain = whatever
-_mongodb_tables = mongodb:_mongodb proxy:mongodb:_proxy_mongodb
+_mongodb_tables = mongodb:_mongodb debug:mongodb:_debug_mongodb
proxy:mongodb:_proxy_mongodb debug:proxy:mongodb:_debug_proxy_mongodb
proxy:debug:mongodb:_proxy_debug_mongodb
_mysql_domain = whatever
-_mysql_tables = mysql:_mysql proxy:mysql:_proxy_mysql
+_mysql_tables = mysql:_mysql debug:mysql:_debug_mysql proxy:mysql:_proxy_mysql
debug:proxy:mysql:_debug_proxy_mysql proxy:debug:mysql:_proxy_debug_mysql
_pgsql_domain = whatever
-_pgsql_tables = pgsql:_pgsql proxy:pgsql:_proxy_pgsql
+_pgsql_tables = pgsql:_pgsql debug:pgsql:_debug_pgsql proxy:pgsql:_proxy_pgsql
debug:proxy:pgsql:_debug_proxy_pgsql proxy:debug:pgsql:_proxy_debug_pgsql
+_proxy_debug_ldap_domain = whatever
+_proxy_debug_memcache_domain = whatever
+_proxy_debug_mongodb_domain = whatever
+_proxy_debug_mysql_domain = whatever
+_proxy_debug_pgsql_domain = whatever
+_proxy_debug_sqlite_domain = whatever
_proxy_ldap_domain = whatever
_proxy_memcache_domain = whatever
_proxy_mongodb_domain = whatever
@@ -15,18 +33,36 @@ _proxy_mysql_domain = whatever
_proxy_pgsql_domain = whatever
_proxy_sqlite_domain = whatever
_sqlite_domain = whatever
-_sqlite_tables = sqlite:_sqlite proxy:sqlite:_proxy_sqlite
+_sqlite_tables = sqlite:_sqlite debug:sqlite:_debug_sqlite
proxy:sqlite:_proxy_sqlite debug:proxy:sqlite:_debug_proxy_sqlite
proxy:debug:sqlite:_proxy_debug_sqlite
config_directory = .
header_checks = $_ldap_tables $_memcache_tables $_mongodb_tables
$_mysql_tables $_pgsql_tables $_sqlite_tables
-./postconf: warning: ./main.cf: unused parameter: _proxy_ldap_domainx=whatever
-./postconf: warning: ./main.cf: unused parameter:
_proxy_sqlite_domainx=whatever
-./postconf: warning: ./main.cf: unused parameter:
_proxy_mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_mysql_domainx=whatever
./postconf: warning: ./main.cf: unused parameter: _memcache_domainx=whatever
-./postconf: warning: ./main.cf: unused parameter: _proxy_mysql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_sqlite_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_memcache_domainx=whatever
./postconf: warning: ./main.cf: unused parameter:
_proxy_memcache_domainx=whatever
-./postconf: warning: ./main.cf: unused parameter: _mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _proxy_ldap_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_sqlite_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _proxy_mysql_domainx=whatever
./postconf: warning: ./main.cf: unused parameter: _ldap_domainx=whatever
-./postconf: warning: ./main.cf: unused parameter: _sqlite_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_mysql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_ldap_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_pgsql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_pgsql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_pgsql_domainx=whatever
./postconf: warning: ./main.cf: unused parameter: _proxy_pgsql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _sqlite_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _debug_ldap_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_mysql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_debug_ldap_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_sqlite_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_memcache_domainx=whatever
./postconf: warning: ./main.cf: unused parameter: _mysql_domainx=whatever
./postconf: warning: ./main.cf: unused parameter: _pgsql_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_memcache_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_proxy_mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter: _mongodb_domainx=whatever
+./postconf: warning: ./main.cf: unused parameter:
_debug_proxy_sqlite_domainx=whatever
diff --git a/src/proxymap/Makefile.in b/src/proxymap/Makefile.in
index efe6e0c87..29dec6a74 100644
--- a/src/proxymap/Makefile.in
+++ b/src/proxymap/Makefile.in
@@ -52,6 +52,7 @@ proxymap.o: ../../include/argv.h
proxymap.o: ../../include/attr.h
proxymap.o: ../../include/check_arg.h
proxymap.o: ../../include/dict.h
+proxymap.o: ../../include/dict_debug.h
proxymap.o: ../../include/dict_pipe.h
proxymap.o: ../../include/dict_proxy.h
proxymap.o: ../../include/dict_union.h
diff --git a/src/proxymap/proxymap.c b/src/proxymap/proxymap.c
index c0af411f6..9fc1159e8 100644
--- a/src/proxymap/proxymap.c
+++ b/src/proxymap/proxymap.c
@@ -232,6 +232,7 @@
#include <htable.h>
#include <stringops.h>
#include <dict.h>
+#include <dict_debug.h>
#include <dict_pipe.h>
#include <dict_union.h>
@@ -307,6 +308,7 @@ static char *get_nested_dict_name(char *type_name)
} *prefix, prefixes[] = {
DICT_TYPE_UNION ":", (sizeof(DICT_TYPE_UNION ":") - 1),
DICT_TYPE_PIPE ":", (sizeof(DICT_TYPE_PIPE ":") - 1),
+ DICT_TYPE_DEBUG ":", (sizeof(DICT_TYPE_DEBUG ":") - 1),
};
#define COUNT_OF(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/src/util/Makefile.in b/src/util/Makefile.in
index 7c99ae23a..b9d70dbd2 100644
--- a/src/util/Makefile.in
+++ b/src/util/Makefile.in
@@ -104,7 +104,8 @@ 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 \
+ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_debug.h dict_env.h \
+ dict_ht.h \
dict_lmdb.h dict_ni.h dict_nis.h dict_nisplus.h dict_pcre.h
dict_regexp.h \
dict_sdbm.h dict_static.h dict_tcp.h dict_unix.h dir_forest.h \
events.h exec_command.h find_inet.h fsspace.h fullname.h \
@@ -658,7 +659,7 @@ dict_tests: all dict_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 dict_stream_test dict_inline_regexp_test \
- dict_inline_cidr_test
+ dict_inline_cidr_test dict_debug_test
dict_pcre_tests: dict_pcre_test miss_endif_pcre_test dict_pcre_file_test \
dict_inline_pcre_test
@@ -1113,6 +1114,11 @@ dict_inline_cidr_test: dict_open dict_inline_cidr.ref
diff dict_inline_cidr.ref dict_inline_cidr.tmp
rm -f dict_inline_cidr.tmp
+dict_debug_test: dict_open dict_debug_test.sh dict_debug_test.ref
+ $(SHLIB_ENV) ./dict_debug_test.sh >dict_debug_test.tmp 2>&1
+ diff dict_debug_test.ref dict_debug_test.tmp
+ rm -f dict_debug_test.tmp
+
find_inet_test: find_inet find_inet.ref
$(SHLIB_ENV) ${VALGRIND} ./find_inet >find_inet.tmp 2>&1
diff find_inet.ref find_inet.tmp
@@ -1545,6 +1551,7 @@ dict_debug.o: argv.h
dict_debug.o: check_arg.h
dict_debug.o: dict.h
dict_debug.o: dict_debug.c
+dict_debug.o: dict_debug.h
dict_debug.o: msg.h
dict_debug.o: myflock.h
dict_debug.o: mymalloc.h
@@ -1672,6 +1679,7 @@ dict_open.o: dict_cdb.h
dict_open.o: dict_cidr.h
dict_open.o: dict_db.h
dict_open.o: dict_dbm.h
+dict_open.o: dict_debug.h
dict_open.o: dict_env.h
dict_open.o: dict_fail.h
dict_open.o: dict_ht.h
diff --git a/src/util/dict_debug.c b/src/util/dict_debug.c
index 46634d40c..99bc59c50 100644
--- a/src/util/dict_debug.c
+++ b/src/util/dict_debug.c
@@ -11,6 +11,13 @@
/*
/* DICT *DICT_DEBUG(dict_handle)
/* DICT *dict_handle;
+/*
+/* #include <dict_debug.h>
+/*
+/* DICT *dict_debug_open(name, open_flags, dict_flags);
+/* const char *name;
+/* int open_flags;
+/* int dict_flags;
/* DESCRIPTION
/* dict_debug() encapsulates the given dictionary object and returns
/* a proxy object that logs all access to the encapsulated object.
@@ -21,6 +28,12 @@
/* the object's debugging flag is not set, and that otherwise encapsulates
/* the object with dict_debug(). This macro simplifies usage by avoiding
/* clumsy expressions. The macro evaluates its argument multiple times.
+/*
+/* dict_debug_open() is similar to dict_debug() except the underlying
+/* table's handle is registered as \fIname\fR, which has the form
+/* "\fItype\fB:\fIname\fR". If no such registration exists yet, the
+/* underlying table is first opened as if by a call to
+/* dict_open(\fIname\fR, \fIopen_flags\fR, \fIdict_flags\fR).
/* DIAGNOSTICS
/* Fatal errors: out of memory.
/* LICENSE
@@ -32,17 +45,21 @@
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
+/*
+/* Richard Hansen <[email protected]> (dict_debug_open(), © 2025)
/*--*/
/* System libraries. */
#include <sys_defs.h>
+#include <string.h>
/* Utility library. */
#include <msg.h>
#include <mymalloc.h>
#include <dict.h>
+#include "dict_debug.h"
/* Application-specific. */
@@ -62,7 +79,10 @@ static const char *dict_debug_lookup(DICT *dict, const char
*key)
real_dict->flags = dict->flags;
result = dict_get(real_dict, key);
dict->flags = real_dict->flags;
- msg_info("%s:%s lookup: \"%s\" = \"%s\"", dict->type, dict->name, key,
+ const char *type = dict->type, *sep = ":", *name = dict->name;
+ if (strcmp(type, DICT_TYPE_DEBUG) == 0)
+ type = sep = "";
+ msg_info("%s%s%s lookup: \"%s\" = \"%s\"", type, sep, name, key,
result ? result : real_dict->error ? "error" : "not_found");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
}
@@ -78,7 +98,10 @@ static int dict_debug_update(DICT *dict, const char *key,
const char *value)
real_dict->flags = dict->flags;
result = dict_put(real_dict, key, value);
dict->flags = real_dict->flags;
- msg_info("%s:%s update: \"%s\" = \"%s\": %s", dict->type, dict->name,
+ const char *type = dict->type, *sep = ":", *name = dict->name;
+ if (strcmp(type, DICT_TYPE_DEBUG) == 0)
+ type = sep = "";
+ msg_info("%s%s%s update: \"%s\" = \"%s\": %s", type, sep, name,
key, value, result == 0 ? "success" : real_dict->error ?
"error" : "failed");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
@@ -95,7 +118,10 @@ static int dict_debug_delete(DICT *dict, const char *key)
real_dict->flags = dict->flags;
result = dict_del(real_dict, key);
dict->flags = real_dict->flags;
- msg_info("%s:%s delete: \"%s\": %s", dict->type, dict->name, key,
+ const char *type = dict->type, *sep = ":", *name = dict->name;
+ if (strcmp(type, DICT_TYPE_DEBUG) == 0)
+ type = sep = "";
+ msg_info("%s%s%s delete: \"%s\": %s", type, sep, name, key,
result == 0 ? "success" : real_dict->error ?
"error" : "failed");
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
@@ -113,11 +139,14 @@ static int dict_debug_sequence(DICT *dict, int function,
real_dict->flags = dict->flags;
result = dict_seq(real_dict, function, key, value);
dict->flags = real_dict->flags;
+ const char *type = dict->type, *sep = ":", *name = dict->name;
+ if (strcmp(type, DICT_TYPE_DEBUG) == 0)
+ type = sep = "";
if (result == 0)
- msg_info("%s:%s sequence: \"%s\" = \"%s\"", dict->type, dict->name,
+ msg_info("%s%s%s sequence: \"%s\" = \"%s\"", type, sep, name,
*key, *value);
else
- msg_info("%s:%s sequence: found EOF", dict->type, dict->name);
+ msg_info("%s%s%s sequence: found EOF", type, sep, name);
DICT_ERR_VAL_RETURN(dict, real_dict->error, result);
}
@@ -127,7 +156,10 @@ static void dict_debug_close(DICT *dict)
{
DICT_DEBUG *dict_debug = (DICT_DEBUG *) dict;
- dict_close(dict_debug->real_dict);
+ if (strcmp(dict->type, DICT_TYPE_DEBUG) == 0)
+ dict_unregister(dict->name);
+ else
+ dict_close(dict_debug->real_dict);
dict_free(dict);
}
@@ -148,3 +180,32 @@ DICT *dict_debug(DICT *real_dict)
dict_debug->real_dict = real_dict;
return (&dict_debug->dict);
}
+
+DICT *dict_debug_open(const char *name, int open_flags, int dict_flags)
+{
+ static const char myname[] = "dict_debug_open";
+ if (msg_verbose)
+ msg_info("%s: %s", myname, name);
+ // Reuse a previously registered table if present. This prevents a config
+ // containing both debug:foo:bar and foo:bar from creating two different
+ // DICT objects for foo:bar.
+ DICT *real_dict = dict_handle(name);
+ if (real_dict == 0)
+ real_dict = dict_open(name, open_flags, dict_flags);
+ dict_register(name, real_dict);
+ DICT_DEBUG *dd = (DICT_DEBUG *) dict_debug(real_dict);
+ // Unlike tables returned from dict_debug(), debug:* tables do not have the
+ // same type and name as the underlying table. They instead have type
+ // "debug" and name equal to the underlying table's registered spec. This
+ // ensures that the logged spec exactly matches the user's configuration,
+ // even if they do something silly like debug:debug:foo:bar, and it
+ // guarantees that the call to dict_unregister() in dict_debug_close()
+ // exactly matches the call to dict_register() above.
+ myfree(dd->dict.type);
+ myfree(dd->dict.name);
+ dd->dict.type = mystrdup(DICT_TYPE_DEBUG);
+ dd->dict.name = mystrdup(name);
+ // TODO(rhansen): Shouldn't this be done in dict_debug()?
+ dd->dict.owner = real_dict->owner;
+ return &dd->dict;
+}
diff --git a/src/util/dict_debug.h b/src/util/dict_debug.h
new file mode 100644
index 000000000..bbf56c6c6
--- /dev/null
+++ b/src/util/dict_debug.h
@@ -0,0 +1,34 @@
+#ifndef _DICT_DEBUG_H_INCLUDED_
+#define _DICT_DEBUG_H_INCLUDED_
+
+/*++
+/* NAME
+/* dict_debug 3h
+/* SUMMARY
+/* dictionary manager interface for "debug" tables
+/* SYNOPSIS
+/* #include <dict_debug.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <dict.h>
+
+ /*
+ * External interface.
+ */
+#define DICT_TYPE_DEBUG "debug"
+
+extern DICT *dict_debug_open(const char *, int, int);
+
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Richard Hansen <[email protected]> (© 2025)
+/*--*/
+
+#endif
diff --git a/src/util/dict_debug_test.ref b/src/util/dict_debug_test.ref
new file mode 100644
index 000000000..0c31d1ab1
--- /dev/null
+++ b/src/util/dict_debug_test.ref
@@ -0,0 +1,51 @@
++ ./dict_open debug: read
+./dict_open: fatal: open dictionary: expecting "type:name" form instead of
"debug:"
++ ./dict_open debug:missing_colon_and_name read
+./dict_open: fatal: open dictionary: expecting "type:name" form instead of
"missing_colon_and_name"
++ ./dict_open debug:static:{space in name} read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: static:{space in name} lookup: "k" = "space in name"
+k=space in name
++ ./dict_open debug:debug:static:value read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: static:value lookup: "k" = "value"
+./dict_open: debug:static:value lookup: "k" = "value"
+k=value
++ ./dict_open debug:internal:name write
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: internal:name lookup: "k" = "not_found"
+k: not found
+> put k=v
+./dict_open: internal:name update: "k" = "v": success
+> get k
+./dict_open: internal:name lookup: "k" = "v"
+k=v
+> first
+./dict_open: internal:name sequence: "k" = "v"
+k=v
+> next
+./dict_open: internal:name sequence: found EOF
+not found
+> del k
+./dict_open: internal:name delete: "k": success
+k: deleted
+> get k
+./dict_open: internal:name lookup: "k" = "not_found"
+k: not found
+> del k
+./dict_open: internal:name delete: "k": failed
+k: not found
+> first
+./dict_open: internal:name sequence: found EOF
+not found
++ ./dict_open debug:fail:{oh no} read
+owner=trusted (uid=2147483647)
+> get k
+./dict_open: fail:{oh no} lookup: "k" = "error"
+k: error
+> first
+./dict_open: fail:{oh no} sequence: found EOF
+error
diff --git a/src/util/dict_debug_test.sh b/src/util/dict_debug_test.sh
new file mode 100755
index 000000000..a8c051d80
--- /dev/null
+++ b/src/util/dict_debug_test.sh
@@ -0,0 +1,25 @@
+#!/bin/sh
+set -ex
+! ${VALGRIND} ./dict_open 'debug:' read </dev/null || exit 1
+! ${VALGRIND} ./dict_open 'debug:missing_colon_and_name' read </dev/null ||
exit 1
+${VALGRIND} ./dict_open 'debug:static:{space in name}' read <<EOF
+get k
+EOF
+${VALGRIND} ./dict_open 'debug:debug:static:value' read <<EOF
+get k
+EOF
+${VALGRIND} ./dict_open 'debug:internal:name' write <<EOF
+get k
+put k=v
+get k
+first
+next
+del k
+get k
+del k
+first
+EOF
+${VALGRIND} ./dict_open 'debug:fail:{oh no}' read <<EOF
+get k
+first
+EOF
diff --git a/src/util/dict_open.c b/src/util/dict_open.c
index c3b90d497..bc42c06fc 100644
--- a/src/util/dict_open.c
+++ b/src/util/dict_open.c
@@ -337,6 +337,7 @@
#include <msg.h>
#include <dict.h>
#include <dict_cdb.h>
+#include <dict_debug.h>
#include <dict_env.h>
#include <dict_unix.h>
#include <dict_tcp.h>
@@ -415,6 +416,7 @@ static const DICT_OPEN_INFO dict_open_info[] = {
DICT_TYPE_LMDB, dict_lmdb_open, mkmap_lmdb_open,
#endif
#endif /* !USE_DYNAMIC_MAPS */
+ DICT_TYPE_DEBUG, dict_debug_open, 0,
0,
};
--
2.49.0
_______________________________________________
Postfix-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]