Cleanup: unbroke Valgrind tests. Files: postmulti/Makefile.in,
proxymap/Makefile.in.
+
+ Cleanup: missing "4.7.1" enhanced status code in Milter
+ "shutdown" response. File: milter/milter8.c.
+
+20260119
+
+ Cleanup: change the domain name length limit from 1024 to
+ MAXDNAME (defined in <arpa/nameser.h>) which is 1025. File:
+ src/dns/dns.h.
+
+20260126
+
+ Cleanup: postconf logged errors when a 'raw parameter' $name
+ (such as $smtpd_expansion_filter) appeared in the value of
+ a non-raw parameter. The solution was to selectively disable
+ mac_expand() recursion for 'raw' parameters. Files:
+ util/mac_expand.[hc], postconf/postconf_lookup.c
+
+20260127
+
+ Usability: when building on a Linux system that has no
+ Berkeley DB header file installed, "make makefiles" will
+ now suggest building with -DNO_DB instead. File: makedefs.
+
+ Usability: when building with -DNO_DB, makedefs will now
+ remind the user to override the default_database_type and
+ default_cache_db_type with names other than 'hash' or
+ 'btree'. File: makedefs.
+
+ Added notes about MariaDB support, suggested by Otto
+ Kekäläinen. Files: proto/MYSQL_README.html proto/mysql_table.
+
+ Feature: "postconf -PP service/type/parameter" will list
+ parameters that are not set in master.cf. This is useful
+ because the value of such a parameter may depend on some
+ other parameter setting in master.cf. The initial use case
+ is to support tools that scan Postfix configurations for
+ deprecated lookup tables. A typical example is "postconf
+ -PPx '*/*/proxy_read_maps". Files: postconf/postconf.[hc],
+ postconf/postconf_master.c, postconf/Makefile.in.
I\bIn\bnt\btr\bro\bod\bdu\buc\bct\bti\bio\bon\bn
-The Postfix mysql map type allows you to hook up Postfix to a MySQL database.
-This implementation allows for multiple mysql databases: you can use one for a
-virtual(5) table, one for an access(5) table, and one for an aliases(5) table
-if you want. You can specify multiple servers for the same database, so that
-Postfix can switch to a good database server if one goes bad.
+The Postfix mysql map type allows you to hook up Postfix to MySQL or MariaDB
+databases. This implementation allows for multiple databases: you can use one
+for a virtual(5) table, one for an access(5) table, and one for an aliases(5)
+table if you want. You can specify multiple servers for the same database, so
+that Postfix can switch to a good database server if one goes bad.
+
+Even though the component name is 'mysql' in Postfix, MariaDB/MySQL client and
+servers can be used interchangeably as the functionality Postfix relies on is
+available in both. However, the code bases may still diverge in the future.
Busy mail servers using mysql maps will generate lots of concurrent mysql
clients, so the mysql server(s) should be run with this fact in mind. You can
https://www.mysql.com/downloads/
+Many Linux distributions compile Postfix MySQL support using the equivalent
+client library from MariaDB:
+
+ https://mariadb.org/connector-c/
+
In order to build Postfix with mysql map support, you will need to add -
DHAS_MYSQL and -I for the directory containing the mysql headers, and the
mysqlclient library (and libm) to AUXLIBS_MYSQL, for example:
#!/bin/sh
# Fix grep -[EF] for systems that require the historical forms egrep
-# and fgrep. Run this script in the top-level Postfix directory as
+# and fgrep. Run this script from the top-level Postfix directory as
# sh auxiliary/fix-grep/fix-grep.sh
# Use only historical grep syntax.
<head>
-<title>Postfix MySQL Howto</title>
+<title>Postfix MySQL/MariaDB Howto</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
<h2>Introduction</h2>
-<p> The Postfix mysql map type allows you to hook up Postfix to a
-MySQL database. This implementation allows for multiple mysql
+<p> The Postfix mysql map type allows you to hook up Postfix to
+MySQL or MariaDB databases. This implementation allows for multiple
databases: you can use one for a <a href="virtual.5.html">virtual(5)</a> table, one for an
<a href="access.5.html">access(5)</a> table, and one for an <a href="aliases.5.html">aliases(5)</a> table if you want. You
can specify multiple servers for the same database, so that Postfix
can switch to a good database server if one goes bad. </p>
+<p> Even though the component name is 'mysql' in Postfix, MariaDB/MySQL
+client and servers can be used interchangeably as the functionality
+Postfix relies on is available in both. However, the code bases may
+still diverge in the future. </p>
+
<p> Busy mail servers using mysql maps will generate lots of
concurrent mysql clients, so the mysql server(s) should be run with
this fact in mind. You can reduce the number of concurrent mysql
<p> <a href="https://www.mysql.com/downloads/">https://www.mysql.com/downloads/</a> </p>
</blockquote>
+<p> Many Linux distributions compile Postfix MySQL support using
+the equivalent client library from MariaDB: </p>
+
+<blockquote>
+ <p> <a href="https://mariadb.org/connector-c/">https://mariadb.org/connector-c/</a> </p>
+</blockquote>
+
<p> In order to build Postfix with mysql map support, you will need to add
-DHAS_MYSQL and -I for the directory containing the mysql headers, and
the mysqlclient library (and libm) to <a href="MYSQL_README.html">AUXLIBS_MYSQL</a>, for example: </p>
MYSQL_TABLE(5) MYSQL_TABLE(5)
<b><a name="name">NAME</a></b>
- mysql_table - Postfix MySQL client configuration
+ mysql_table - Postfix MySQL/MariaDB client configuration
<b><a name="synopsis">SYNOPSIS</a></b>
<b>postmap -q "</b><i>string</i><b>" <a href="mysql_table.5.html">mysql</a>:/etc/postfix/</b><i>filename</i>
The file /etc/postfix/mysql-aliases.cf has the same format as the Post-
fix <a href="postconf.5.html">main.cf</a> file, and can specify the parameters described below.
+ Even though the component name is 'mysql' in Postfix, MariaDB/MySQL
+ client and servers can be used interchangeably as the functionality
+ Postfix relies on is available in both. However, their code bases may
+ still diverge in the future.
+
<b><a name="list_membership">LIST MEMBERSHIP</a></b>
- When using SQL to store lists such as $<a href="postconf.5.html#mynetworks">mynetworks</a>, $<a href="postconf.5.html#mydestination">mydestination</a>,
- $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>, etc., it is important to under-
+ When using SQL to store lists such as $<a href="postconf.5.html#mynetworks">mynetworks</a>, $<a href="postconf.5.html#mydestination">mydestination</a>,
+ $<a href="postconf.5.html#relay_domains">relay_domains</a>, $<a href="postconf.5.html#local_recipient_maps">local_recipient_maps</a>, etc., it is important to under-
stand that the table must store each list member as a separate key. The
- table lookup verifies the *existence* of the key. See "Postfix lists
+ table lookup verifies the *existence* of the key. See "Postfix lists
versus tables" in the <a href="DATABASE_README.html">DATABASE_README</a> document for a discussion.
- Do NOT create tables that return the full list of domains in $<a href="postconf.5.html#mydestination">mydesti</a>-
+ Do NOT create tables that return the full list of domains in $<a href="postconf.5.html#mydestination">mydesti</a>-
<a href="postconf.5.html#mydestination">nation</a> or $<a href="postconf.5.html#relay_domains">relay_domains</a> etc., or IP addresses in $<a href="postconf.5.html#mynetworks">mynetworks</a>.
DO create tables with each matching item as a key and with an arbitrary
- value. With SQL databases it is not uncommon to return the key itself
+ value. With SQL databases it is not uncommon to return the key itself
or a constant value.
<b><a name="mysql_parameters">MYSQL PARAMETERS</a></b>
- <b>hosts</b> The hosts that Postfix will try to connect to and query from.
+ <b>hosts</b> The hosts that Postfix will try to connect to and query from.
Specify <i>unix:</i> for UNIX domain sockets, <i>inet:</i> for TCP connections
(default). Examples:
hosts = inet:host1.some.domain inet:host2.some.domain:port
hosts = host1.some.domain host2.some.domain:port
hosts = unix:/file/name
- The hosts are tried in random order, with all connections over
+ The hosts are tried in random order, with all connections over
UNIX domain sockets being tried before those over TCP. The con-
- nections are automatically closed after being idle for about 1
+ nections are automatically closed after being idle for about 1
minute, and are re-opened as necessary. Postfix versions 2.0 and
earlier do not randomize the host order.
NOTE: if you specify localhost as a hostname (even if you prefix
- it with <i>inet:</i>), MySQL will connect to the default UNIX domain
+ it with <i>inet:</i>), MySQL will connect to the default UNIX domain
socket. In order to instruct MySQL to connect to localhost over
TCP you have to specify
hosts = 127.0.0.1
- NOTE: if the <b>hosts</b> setting specifies only one server, this
- client assumes that the target is a load balancer and will
- reconnect immediately after a single failure. With Postfix ver-
+ NOTE: if the <b>hosts</b> setting specifies only one server, this
+ client assumes that the target is a load balancer and will
+ reconnect immediately after a single failure. With Postfix ver-
sions 3.9 and earlier, specify the same server twice.
<b>user</b>
<b>password</b>
- The user name and password to log into the mysql server. Exam-
+ The user name and password to log into the mysql server. Exam-
ple:
user = someone
password = some_password
dbname = customer_database
<b>charset (default: utf8mb4)</b>
- The default MySQL client character set; this also implies the
+ The default MySQL client character set; this also implies the
collation order.
- This parameter is available with Postfix 3.9 and later. With
- earlier Postfix versions, the default was chosen by the MySQL
+ This parameter is available with Postfix 3.9 and later. With
+ earlier Postfix versions, the default was chosen by the MySQL
implementation (<b>utf8mb4</b> as of MySQL 8.0, <b>latin1</b> historically).
<b>idle_interval (default: 60)</b>
- The number of seconds after which an idle database connection
+ The number of seconds after which an idle database connection
will be closed.
This feature is available in Postfix 3.9 and later.
The number of seconds that a database connection will be skipped
after an error.
- NOTE: if the <b>hosts</b> setting specifies only one server, this
- client assumes that the target is a load balancer and will
- reconnect immediately after a single failure. With Postfix ver-
+ NOTE: if the <b>hosts</b> setting specifies only one server, this
+ client assumes that the target is a load balancer and will
+ reconnect immediately after a single failure. With Postfix ver-
sions 3.9 and earlier, specify the same server twice.
This feature is available in Postfix 3.9 and later.
- <b>query</b> The SQL query template used to search the database, where <b>%s</b> is
- a substitute for the address Postfix is trying to resolve, e.g.
+ <b>query</b> The SQL query template used to search the database, where <b>%s</b> is
+ a substitute for the address Postfix is trying to resolve, e.g.
query = SELECT replacement FROM aliases WHERE mailbox = '%s'
- By default, every query must return a result set (instead of
- storing its results in a table); with "<b>require_result_set = no</b>"
- (Postfix 3.2 and later), the absence of a result set is treated
+ By default, every query must return a result set (instead of
+ storing its results in a table); with "<b>require_result_set = no</b>"
+ (Postfix 3.2 and later), the absence of a result set is treated
as "not found".
This parameter supports the following '%' expansions:
<b>%%</b> This is replaced by a literal '%' character.
- <b>%s</b> This is replaced by the input key. SQL quoting is used
- to make sure that the input key does not add unexpected
+ <b>%s</b> This is replaced by the input key. SQL quoting is used
+ to make sure that the input key does not add unexpected
metacharacters.
<b>%u</b> When the input key is an address of the form user@domain,
- <b>%u</b> is replaced by the SQL quoted local part of the
- address. Otherwise, <b>%u</b> is replaced by the entire search
- string. If the localpart is empty, the query is sup-
+ <b>%u</b> is replaced by the SQL quoted local part of the
+ address. Otherwise, <b>%u</b> is replaced by the entire search
+ string. If the localpart is empty, the query is sup-
pressed and returns no results.
<b>%d</b> When the input key is an address of the form user@domain,
- <b>%d</b> is replaced by the SQL quoted domain part of the
- address. Otherwise, the query is suppressed and returns
+ <b>%d</b> is replaced by the SQL quoted domain part of the
+ address. Otherwise, the query is suppressed and returns
no results.
<b>%[SUD]</b> The upper-case equivalents of the above expansions behave
- in the <b>query</b> parameter identically to their lower-case
- counter-parts. With the <b>result_format</b> parameter (see
- below), they expand the input key rather than the result
+ in the <b>query</b> parameter identically to their lower-case
+ counter-parts. With the <b>result_format</b> parameter (see
+ below), they expand the input key rather than the result
value.
- <b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by the corre-
- sponding most significant component of the input key's
- domain. If the input key is <i>user@mail.example.com</i>, then
+ <b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced by the corre-
+ sponding most significant component of the input key's
+ domain. If the input key is <i>user@mail.example.com</i>, then
%1 is <b>com</b>, %2 is <b>example</b> and %3 is <b>mail</b>. If the input key
- is unqualified or does not have enough domain components
- to satisfy all the specified patterns, the query is sup-
+ is unqualified or does not have enough domain components
+ to satisfy all the specified patterns, the query is sup-
pressed and returns no results.
- The <b>domain</b> parameter described below limits the input keys to
- addresses in matching domains. When the <b>domain</b> parameter is
+ The <b>domain</b> parameter described below limits the input keys to
+ addresses in matching domains. When the <b>domain</b> parameter is
non-empty, SQL queries for unqualified addresses or addresses in
non-matching domains are suppressed and return no results.
- This parameter is available with Postfix 2.2. In prior releases
- the SQL query was built from the separate parameters:
- <b>select_field</b>, <b>table</b>, <b>where_field</b> and <b>additional_conditions</b>. The
+ This parameter is available with Postfix 2.2. In prior releases
+ the SQL query was built from the separate parameters:
+ <b>select_field</b>, <b>table</b>, <b>where_field</b> and <b>additional_conditions</b>. The
mapping from the old parameters to the equivalent query is:
SELECT [<b>select_field</b>]
WHERE [<b>where_field</b>] = '%s'
[<b>additional_conditions</b>]
- The '%s' in the <b>WHERE</b> clause expands to the escaped search
- string. With Postfix 2.2 these legacy parameters are used if
+ The '%s' in the <b>WHERE</b> clause expands to the escaped search
+ string. With Postfix 2.2 these legacy parameters are used if
the <b>query</b> parameter is not specified.
NOTE: DO NOT put quotes around the query parameter.
<b>result_format (default: %s</b>)
Format template applied to result attributes. Most commonly used
- to append (or prepend) text to the result. This parameter sup-
+ to append (or prepend) text to the result. This parameter sup-
ports the following '%' expansions:
<b>%%</b> This is replaced by a literal '%' character.
- <b>%s</b> This is replaced by the value of the result attribute.
+ <b>%s</b> This is replaced by the value of the result attribute.
When result is empty it is skipped.
<b>%u</b> When the result attribute value is an address of the form
- user@domain, <b>%u</b> is replaced by the local part of the
- address. When the result has an empty localpart it is
+ user@domain, <b>%u</b> is replaced by the local part of the
+ address. When the result has an empty localpart it is
skipped.
- <b>%d</b> When a result attribute value is an address of the form
- user@domain, <b>%d</b> is replaced by the domain part of the
- attribute value. When the result is unqualified it is
+ <b>%d</b> When a result attribute value is an address of the form
+ user@domain, <b>%d</b> is replaced by the domain part of the
+ attribute value. When the result is unqualified it is
skipped.
<b>%[SUD1-9]</b>
- The upper-case and decimal digit expansions interpolate
- the parts of the input key rather than the result. Their
- behavior is identical to that described with <b>query</b>, and
- in fact because the input key is known in advance,
- queries whose key does not contain all the information
- specified in the result template are suppressed and
+ The upper-case and decimal digit expansions interpolate
+ the parts of the input key rather than the result. Their
+ behavior is identical to that described with <b>query</b>, and
+ in fact because the input key is known in advance,
+ queries whose key does not contain all the information
+ specified in the result template are suppressed and
return no results.
For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]" allows one to use
a mailHost attribute as the basis of a <a href="transport.5.html">transport(5)</a> table. After
- applying the result format, multiple values are concatenated as
+ applying the result format, multiple values are concatenated as
comma separated strings. The expansion_limit and parameter
- explained below allows one to restrict the number of values in
+ explained below allows one to restrict the number of values in
the result, which is especially useful for maps that must return
at most one value.
- The default value <b>%s</b> specifies that each result value should be
+ The default value <b>%s</b> specifies that each result value should be
used as is.
This parameter is available with Postfix 2.2 and later.
NOTE: DO NOT put quotes around the result format!
<b>domain (default: no domain list)</b>
- This is a list of domain names, paths to files, or "<a href="DATABASE_README.html">type:table</a>"
+ This is a list of domain names, paths to files, or "<a href="DATABASE_README.html">type:table</a>"
databases. When specified, only fully qualified search keys with
- a *non-empty* localpart and a matching domain are eligible for
+ a *non-empty* localpart and a matching domain are eligible for
lookup: 'user' lookups, bare domain lookups and "@domain"
- lookups are not performed. This can significantly reduce the
+ lookups are not performed. This can significantly reduce the
query load on the MySQL server.
domain = postfix.org, <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/searchdomains
- It is best not to use SQL to store the domains eligible for SQL
+ It is best not to use SQL to store the domains eligible for SQL
lookups.
This parameter is available with Postfix 2.2 and later.
the input keys are always unqualified.
<b>expansion_limit (default: 0)</b>
- A limit on the total number of result elements returned (as a
+ A limit on the total number of result elements returned (as a
comma separated list) by a lookup against the map. A setting of
- zero disables the limit. Lookups fail with a temporary error if
- the limit is exceeded. Setting the limit to 1 ensures that
+ zero disables the limit. Lookups fail with a temporary error if
+ the limit is exceeded. Setting the limit to 1 ensures that
lookups do not return multiple values.
<b>option_file</b>
- Read options from the given file instead of the default my.cnf
- location. This reads options from the <b>[client]</b> option group,
+ Read options from the given file instead of the default my.cnf
+ location. This reads options from the <b>[client]</b> option group,
optionally followed by options from the group given with
<b>option_group</b>.
This parameter is available with Postfix 2.11 and later.
<b>option_group (default: Postfix</b> ><b>=3.2: client,</b> <<b>= 3.1: empty)</b>
- Read options from the given group of the mysql options file,
+ Read options from the given group of the mysql options file,
after reading options from the <b>[client]</b> group.
- Postfix 3.2 and later read <b>[client]</b> option group settings by
- default. To disable this specify no <b>option_file</b> and specify
+ Postfix 3.2 and later read <b>[client]</b> option group settings by
+ default. To disable this specify no <b>option_file</b> and specify
"<b>option_group =</b>" (i.e. an empty value).
- Postfix 3.1 and earlier don't read <b>[client]</b> option group set-
- tings unless a non-empty <b>option_file</b> or <b>option_group</b> value are
+ Postfix 3.1 and earlier don't read <b>[client]</b> option group set-
+ tings unless a non-empty <b>option_file</b> or <b>option_group</b> value are
specified. To enable this, specify, for example, "<b>option_group =</b>
<b>client</b>".
This parameter is available with Postfix 2.11 and later.
<b>require_result_set (default: yes)</b>
- If "<b>yes</b>", require that every query returns a result set. If
+ If "<b>yes</b>", require that every query returns a result set. If
"<b>no</b>", treat the absence of a result set as "not found".
This parameter is available with Postfix 3.2 and later.
<b><a name="tls-related_settings">TLS-RELATED SETTINGS</a></b>
- See <a href="https://dev.mysql.com/doc/c-api/en/mysql-options.html">https://dev.mysql.com/doc/c-api/en/mysql-options.html</a> or
+ See <a href="https://dev.mysql.com/doc/c-api/en/mysql-options.html">https://dev.mysql.com/doc/c-api/en/mysql-options.html</a> or
<a href="https://mariadb.com/kb/en/mysql_optionsv/">https://mariadb.com/kb/en/mysql_optionsv/</a> for details of the underlying
MYSQL_OPT_SSL_* features.
This parameter is available with Postfix 2.11 and later.
<b>tls_key_file</b>
- File containing the private key corresponding to <b>tls_cert_file</b>.
+ File containing the private key corresponding to <b>tls_cert_file</b>.
This parameter is available with Postfix 2.11 and later.
<b>tls_CAfile</b>
- File containing X509 certificates for all of the Certification
- Authorities the client will recognize. Takes precedence over
+ File containing X509 certificates for all of the Certification
+ Authorities the client will recognize. Takes precedence over
<b>tls_CApath</b>.
This parameter is available with Postfix 2.11 and later.
<b>tls_CApath</b>
- Directory containing X509 Certification Authority certificates
+ Directory containing X509 Certification Authority certificates
in separate individual files.
This parameter is available with Postfix 2.11 and later.
This parameter is available with Postfix 2.11 and later.
<b>tls_verify_cert (default: no)</b>
- Verify that the server's name matches the common name in the
+ Verify that the server's name matches the common name in the
certificate.
This parameter is available with Postfix 2.11 and later.
<b><a name="using_mysql_stored_procedures">USING MYSQL STORED PROCEDURES</a></b>
- Postfix 3.2 and later support calling a stored procedure instead of
+ Postfix 3.2 and later support calling a stored procedure instead of
using a SELECT statement in the query, e.g.
<b>query</b> = CALL lookup('%s')
The previously described '%' expansions can be used in the parameter(s)
to the stored procedure.
- By default, every stored procedure call must return a result set, i.e.
- every code path must execute a SELECT statement that returns a result
+ By default, every stored procedure call must return a result set, i.e.
+ every code path must execute a SELECT statement that returns a result
set (instead of storing its results in a table). With
- "<b>require_result_set = no</b>", the absence of a result set is treated as
+ "<b>require_result_set = no</b>", the absence of a result set is treated as
"not found".
- A stored procedure must not return multiple result sets. That is,
- there must be no code path that executes multiple SELECT statements
+ A stored procedure must not return multiple result sets. That is,
+ there must be no code path that executes multiple SELECT statements
that return a result (instead of storing their results in a table).
- The following is an example of a stored procedure returning a single
+ The following is an example of a stored procedure returning a single
result set:
CREATE [DEFINER=`user`@`host`] PROCEDURE
END
<b>OBSOLETE MAIN.CF PARAMETERS</b>
- For compatibility with other Postfix lookup tables, MySQL parameters
- can also be defined in <a href="postconf.5.html">main.cf</a>. In order to do that, specify as MySQL
- source a name that doesn't begin with a slash or a dot. The MySQL
- parameters will then be accessible as the name you've given the source
- in its definition, an underscore, and the name of the parameter. For
- example, if the map is specified as "<a href="mysql_table.5.html">mysql</a>:<i>mysqlname</i>", the parameter
+ For compatibility with other Postfix lookup tables, MySQL parameters
+ can also be defined in <a href="postconf.5.html">main.cf</a>. In order to do that, specify as MySQL
+ source a name that doesn't begin with a slash or a dot. The MySQL
+ parameters will then be accessible as the name you've given the source
+ in its definition, an underscore, and the name of the parameter. For
+ example, if the map is specified as "<a href="mysql_table.5.html">mysql</a>:<i>mysqlname</i>", the parameter
"hosts" would be defined in <a href="postconf.5.html">main.cf</a> as "<i>mysqlname</i>_hosts".
- Note: with this form, the passwords for the MySQL sources are written
- in <a href="postconf.5.html">main.cf</a>, which is normally world-readable. Support for this form
+ Note: with this form, the passwords for the MySQL sources are written
+ in <a href="postconf.5.html">main.cf</a>, which is normally world-readable. Support for this form
will be removed in a future Postfix version.
<b><a name="obsolete_query_interface">OBSOLETE QUERY INTERFACE</a></b>
- This section describes an interface that is deprecated as of Postfix
- 2.2. It is replaced by the more general <b>query</b> interface described
- above. If the <b>query</b> parameter is defined, the legacy parameters
- described here ignored. Please migrate to the new interface as the
+ This section describes an interface that is deprecated as of Postfix
+ 2.2. It is replaced by the more general <b>query</b> interface described
+ above. If the <b>query</b> parameter is defined, the legacy parameters
+ described here ignored. Please migrate to the new interface as the
legacy interface may be removed in a future release.
- The following parameters can be used to fill in a SELECT template
+ The following parameters can be used to fill in a SELECT template
statement of the form:
SELECT [<b>select_field</b>]
[<b>additional_conditions</b>]
The specifier %s is replaced by the search string, and is escaped so if
- it contains single quotes or other odd characters, it will not cause a
+ it contains single quotes or other odd characters, it will not cause a
parse error, or worse, a security problem.
<b>select_field</b>
vices and all parameters), formatted as "<i>service/type/parame-</i>
<i>ter=value</i>", one per line. Specify <b>-Pf</b> to fold long lines.
+ Specify multiple <b>-P</b> options to also list service parameters that
+ are not set in <a href="master.5.html">master.cf</a>. This is useful with <b>-x</b> to evaluate the
+ impact of <a href="master.5.html">master.cf</a> overrides on other parameter settings.
+
Specify one or more "<i>service/type/parameter</i>" instances on the
<a href="postconf.1.html"><b>postconf</b>(1)</a> command line to limit the output to parameters of
interest. Trailing parameter name or service type fields that
# by including <db.h> and by linking with -ldb
echo "No <db.h> include file found." 1>&2
echo "Install the appropriate db*-devel package first." 1>&2
+ echo "Alternatively, build with CCARGS=\"-NO_DB ...\"" 1>&2
exit 1
fi
SYSLIBS="-ldb"
# by including <db.h> and by linking with -ldb
echo "No <db.h> include file found." 1>&2
echo "Install the appropriate db*-devel package first." 1>&2
+ echo "Alternatively, build with CCARGS=\"-NO_DB ...\"" 1>&2
exit 1
fi
SYSLIBS="-ldb"
# by including <db.h> and by linking with -ldb
echo "No <db.h> include file found." 1>&2
echo "Install the appropriate db*-devel package first." 1>&2
+ echo "Alternatively, build with CCARGS=\"-NO_DB ...\"" 1>&2
exit 1
fi
SYSLIBS="-ldb"
done; exit 1) || error "invalid option '$opt' in POSTFIX_INSTALL_OPTS"
done
+# If -DNO_DB is specified then 'hash' and 'btree' will be unavailable.
+
+check_no_db_overrides()
+{
+ trap 'rm -f makedefs.test makedefs.test.[co]' 0 1 2 3 15
+ cat src/util/sys_defs.h >makedefs.test.c
+ cat >>makedefs.test.c <<'EOF'
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+int main(void)
+{
+ struct def_info {
+ const char *mac_name;
+ const char *parm_name;
+ const char *def_type;
+ const char *problem;
+ };
+ struct def_info def_infos[] = {
+ {"DEF_DB_TYPE", "default_database_type", DEF_DB_TYPE},
+ {"DEF_CACHE_DB_TYPE", "default_cache_db_type", DEF_CACHE_DB_TYPE},
+ };
+ const char *bdb_types[] = {"hash", "btree"};
+ struct def_info *pdef_info;
+ const char *const * pbdb_type;
+ const char *three_bs = "\\\\\\";
+ int status = 0;
+
+ for (pdef_info = def_infos; pdef_info < def_infos + 2; pdef_info++) {
+ for (pbdb_type = bdb_types; pbdb_type < bdb_types + 2; pbdb_type++) {
+ if (strcmp(pdef_info->def_type, *pbdb_type) == 0) {
+ pdef_info->problem = *pbdb_type;
+ status = 1;
+ }
+ }
+ }
+ if (status != 0) {
+ fprintf(stderr, "\nBuilding with -DNO_DB, but at least one default "
+ "setting still\nrequires 'hash' or 'btree':\n");
+ for (pdef_info = def_infos; pdef_info < def_infos + 2; pdef_info++) {
+ if (pdef_info->problem) {
+ fprintf(stderr, " %s=%s\n", pdef_info->parm_name,
+ pdef_info->problem);
+ }
+ }
+ fprintf(stderr, "\nTo fix, specify types other than 'hash' or 'btree', "
+ "for example:\n make makefiles ... \\\n ");
+ for (pdef_info = def_infos; pdef_info < def_infos + 2; pdef_info++) {
+ if (pdef_info->problem) {
+ fprintf(stderr, " %s=lmdb", pdef_info->parm_name);
+ }
+ }
+ fprintf(stderr, " ...\n\nOr, using older syntax:\n");
+ fprintf(stderr, " make makefiles ... \\\n CCARGS=\"$CCARGS -DNO_DB");
+ for (pdef_info = def_infos; pdef_info < def_infos + 2; pdef_info++) {
+ if (pdef_info->problem) {
+ fprintf(stderr, " -D%s=%s\"lmdb%s\"",
+ pdef_info->mac_name, three_bs, three_bs);
+ }
+ }
+ fprintf(stderr, " ...\" ...\n\n");
+ }
+ exit(status);
+}
+EOF
+ eval ${CC-gcc} ${CCARGS} -D$SYSTYPE -o makedefs.test makedefs.test.c || exit 1
+ ./makedefs.test || exit 1
+ rm -f makedefs.test makedefs.test.[co]
+}
+
+case "$CCARGS" in
+ *-DNO_DB*) check_no_db_overrides || exit 1;;
+esac
+
# Finally...
sed 's/ */ /g' <<EOF
"\fIservice/type/parameter=value\fR", one per line. Specify
\fB\-Pf\fR to fold long lines.
+Specify multiple \fB\-P\fR options to also list service parameters
+that are not set in master.cf. This is useful with \fB\-x\fR to
+evaluate the impact of master.cf overrides on other parameter
+settings.
+
Specify one or more "\fIservice/type/parameter\fR" instances
on the \fBpostconf\fR(1) command line to limit the output
to parameters of interest. Trailing parameter name or
.SH NAME
mysql_table
\-
-Postfix MySQL client configuration
+Postfix MySQL/MariaDB client configuration
.SH "SYNOPSIS"
.na
.nf
The file /etc/postfix/mysql\-aliases.cf has the same format as
the Postfix main.cf file, and can specify the parameters
described below.
+
+Even though the component name is 'mysql' in Postfix,
+MariaDB/MySQL client and servers can be used interchangeably as
+the functionality Postfix relies on is available in both. However,
+their code bases may still diverge in the future.
.SH "LIST MEMBERSHIP"
.na
.nf
# Spellchecks text in the HISTORY file, starting with 2022.
-LANG=C; export LANG
+#LANG=C; export LANG
+LANG=en_US.UTF-8; export LANG
sed '1,/^2022/d' HISTORY | spell | grep -F -vxf proto/stop | \
grep -F -vxf proto/stop.spell-cc | \
<head>
-<title>Postfix MySQL Howto</title>
+<title>Postfix MySQL/MariaDB Howto</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel='stylesheet' type='text/css' href='postfix-doc.css'>
<h2>Introduction</h2>
-<p> The Postfix mysql map type allows you to hook up Postfix to a
-MySQL database. This implementation allows for multiple mysql
+<p> The Postfix mysql map type allows you to hook up Postfix to
+MySQL or MariaDB databases. This implementation allows for multiple
databases: you can use one for a virtual(5) table, one for an
access(5) table, and one for an aliases(5) table if you want. You
can specify multiple servers for the same database, so that Postfix
can switch to a good database server if one goes bad. </p>
+<p> Even though the component name is 'mysql' in Postfix, MariaDB/MySQL
+client and servers can be used interchangeably as the functionality
+Postfix relies on is available in both. However, the code bases may
+still diverge in the future. </p>
+
<p> Busy mail servers using mysql maps will generate lots of
concurrent mysql clients, so the mysql server(s) should be run with
this fact in mind. You can reduce the number of concurrent mysql
<p> https://www.mysql.com/downloads/ </p>
</blockquote>
+<p> Many Linux distributions compile Postfix MySQL support using
+the equivalent client library from MariaDB: </p>
+
+<blockquote>
+ <p> https://mariadb.org/connector-c/ </p>
+</blockquote>
+
<p> In order to build Postfix with mysql map support, you will need to add
-DHAS_MYSQL and -I for the directory containing the mysql headers, and
the mysqlclient library (and libm) to AUXLIBS_MYSQL, for example: </p>
# NAME
# mysql_table 5
# SUMMARY
-# Postfix MySQL client configuration
+# Postfix MySQL/MariaDB client configuration
# SYNOPSIS
# \fBpostmap -q "\fIstring\fB" mysql:/etc/postfix/\fIfilename\fR
#
# The file /etc/postfix/mysql-aliases.cf has the same format as
# the Postfix main.cf file, and can specify the parameters
# described below.
+#
+# Even though the component name is 'mysql' in Postfix,
+# MariaDB/MySQL client and servers can be used interchangeably as
+# the functionality Postfix relies on is available in both. However,
+# their code bases may still diverge in the future.
# LIST MEMBERSHIP
# .ad
# .fi
default value with a lookup table File proxymap proxymap c
in file name and in restriction_classes File proxymap proxymap c
proxymap proxymap c
+ src dns dns h
+ postconf postconf hc postconf postconf_master c
+ PPx proxy_read_maps Files postconf postconf hc
fhHjoqvx
joqvx
ajRv
+allparams
Ankit
Kulkarni
Wordsmithing
+Fusté
+Kekäläinen
+MAXDNAME
+unbroke
+PPx
+unbroke
noencryption
nomatch
nostarttls
+mariadb
/*
* How long can a DNS name or single text value be?
*/
-#define DNS_NAME_LEN 1024
+#define DNS_NAME_LEN MAXDNAME /* From <arpa/nameser.h */
/*
* dns_rr_filter.c.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20260111"
+#define MAIL_RELEASE_DATE "20260127"
#define MAIL_VERSION_NUMBER "3.12"
#ifdef SNAPSHOT
} else if (strcasecmp(milter->def_action, "tempfail") == 0) {
reply = "451 4.7.1 Service unavailable - try again later";
} else if (strcasecmp(milter->def_action, "shutdown") == 0) {
- reply = "421 Service unavailable - try again later";
+ reply = "421 4.7.1 Service unavailable - try again later";
} else if (strcasecmp(milter->def_action, "quarantine") == 0) {
reply = "Hdefault_action";
} else {
../../lib/lib$(LIB_PREFIX)dns$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)global$(LIB_SUFFIX) \
../../lib/lib$(LIB_PREFIX)util$(LIB_SUFFIX)
-HTABLE_FIX = NORANDOMIZE=1
+HTABLE_FIX = NORANDOMIZE=1 LD_PRELOAD=../../lib/nosleep.so
.c.o:; $(CC) $(CFLAGS) -c $*.c
test42 test43 test44 test45 test46 test47 test48 test49 test50 test51 \
test52 test53 test54 test55 test56 test57 test58 test59 test60 test61 \
test62 test63 test64 test65 test66 test67 test68 test69 test70 test71 \
- test72 test73 test74 test75 test76 test78 test79 json_tests
+ test72 test73 test74 test75 test76 test78 test79 json_tests80-90 \
+ test91 test92
-json_tests: test80 test81 test82 test83 test84 test85 test86 test87
+json_tests80-90: test80 test81 test82 test83 test84 test85 test86 test87
root_tests:
diff test87.ref test87.tmp
rm -f main.cf master.cf test87.tmp
+# postconf -PP will list parameters not set in master.cf.
+test91: $(PROG) test91.ref
+ rm -f main.cf master.cf test91.tmp
+ touch main.cf master.cf test91.tmp
+ #echo 'foo/unix/proxymap = foo_map' >> test91.tmp
+ #echo 'bar/unix/proxymap = bar_map' >> test91.tmp
+ #echo 'baz/unix/proxymap = baz_map' >> test91.tmp
+ echo 'foo_proxy_write_maps=foo_map' >> main.cf
+ echo 'bar_proxy_write_maps=bar_map' >> main.cf
+ echo 'proxy_write_maps=baz_map' >> main.cf
+ touch -t 197601010000 main.cf
+ echo foo unix - n n - 0 foo >> master.cf
+ echo ' -o proxy_write_maps=$$foo_proxy_write_maps' >> master.cf
+ echo bar unix - n n - 0 bar >> master.cf
+ echo ' -o proxy_write_maps=$$bar_proxy_write_maps' >> master.cf
+ echo baz unix - n n - 0 baz >> master.cf
+ touch -t 197601010000 master.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -xPPc. \
+ '*/*/proxy_write_maps' >test91.tmp 2>&1
+ diff test91.ref test91.tmp
+ rm -f main.cf master.cf test91.tmp
+
+# postconf -PP will list the same parameters as "postconf", but it does
+# that once for every master.cf service, and will show the settings that
+# are in effect for that service.
+test92: $(PROG)
+ rm -f main.cf master.cf test92.tmp
+ touch main.cf master.cf test92.tmp
+ touch -t 197601010000 main.cf
+ echo foo unix - n n - 0 foo >> master.cf
+ touch -t 197601010000 master.cf
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -c. | \
+ grep -E -v '^(process_id|process_name|service_name) =' >test92.tmp
+ $(HTABLE_FIX) $(SHLIB_ENV) $(VALGRIND) ./$(PROG) -PPc. | \
+ sed 's;foo/unix/;;' | \
+ grep -E -v '^(process_id|process_name|service_name) =' | \
+ diff test92.tmp -
+ rm -f main.cf master.cf test92.tmp
+
tidy: clean
depend: $(MAKES)
/* "\fIservice/type/parameter=value\fR", one per line. Specify
/* \fB-Pf\fR to fold long lines.
/*
+/* Specify multiple \fB-P\fR options to also list service parameters
+/* that are not set in master.cf. This is useful with \fB-x\fR to
+/* evaluate the impact of master.cf overrides on other parameter
+/* settings.
+/*
/* Specify one or more "\fIservice/type/parameter\fR" instances
/* on the \fBpostconf\fR(1) command line to limit the output
/* to parameters of interest. Trailing parameter name or
|PCF_SHOW_LOCKS | PCF_SHOW_MAPS | PCF_DUMP_DSN_TEMPL | PCF_MAIN_PARAM \
|PCF_MASTER_ENTRY | PCF_MASTER_FLD | PCF_MASTER_PARAM | PCF_SHOW_TLS,
/* Modifiers. */
+ PCF_MASTER_PP | PCF_EDIT_CONF | PCF_COMMENT_OUT | PCF_EDIT_EXCL,
PCF_SHOW_DEFS | PCF_EDIT_CONF | PCF_SHOW_NONDEF | PCF_COMMENT_OUT \
|PCF_EDIT_EXCL,
PCF_FOLD_LINE | PCF_EDIT_CONF | PCF_COMMENT_OUT | PCF_EDIT_EXCL,
|PCF_SHOW_JSON)},
{PCF_MASTER_PARAM, (PCF_EDIT_CONF | PCF_EDIT_EXCL | PCF_FOLD_LINE \
|PCF_HIDE_NAME | PCF_MAIN_OVER | PCF_SHOW_EVAL \
- |PCF_HIDE_VALUE | PCF_SHOW_JSON)},
+ |PCF_HIDE_VALUE | PCF_SHOW_JSON | PCF_MASTER_PP)},
+ {PCF_MASTER_PP, (PCF_FOLD_LINE \
+ |PCF_HIDE_NAME | PCF_MAIN_OVER | PCF_SHOW_EVAL \
+ |PCF_HIDE_VALUE | PCF_SHOW_JSON | PCF_MASTER_PARAM)},
{PCF_SHOW_JSON, (PCF_MAIN_PARAM | PCF_MASTER_ENTRY | PCF_MASTER_FLD \
|PCF_MASTER_PARAM | PCF_MAIN_OVER | PCF_SHOW_EVAL \
|PCF_SHOW_NONDEF | PCF_SHOW_DEFS)},
"-x", PCF_SHOW_EVAL,
"-X", PCF_EDIT_EXCL,
"-#", PCF_COMMENT_OUT,
+ "-PP", PCF_MASTER_PP,
0,
};
pcf_cmd_mode |= PCF_MAIN_PARAM;
break;
case 'P':
- pcf_cmd_mode |= PCF_MASTER_PARAM;
+ if (pcf_cmd_mode & PCF_MASTER_PARAM)
+ pcf_cmd_mode |= PCF_MASTER_PP;
+ else
+ pcf_cmd_mode |= PCF_MASTER_PARAM;
break;
case 'q':
pcf_cmd_mode &= ~(PCF_WARN_UNUSED_DEPRECATED);
pcf_show_master_fields(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
argv + optind);
else if (pcf_cmd_mode & PCF_MASTER_PARAM)
- pcf_show_master_params(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
- argv + optind);
+ pcf_show_master_params(VSTREAM_OUT, pcf_cmd_mode, param_class,
+ argc - optind, argv + optind);
else
pcf_show_master_entries(VSTREAM_OUT, pcf_cmd_mode, argc - optind,
argv + optind);
#define PCF_SHOW_TLS (1<<21) /* TLS support introspection */
#define PCF_WARN_UNUSED_DEPRECATED (1<<22) /* As the name says */
#define PCF_SHOW_JSON (1 << 23) /* JSON output */
+#define PCF_MASTER_PP (1<<24) /* multiple -P */
#define PCF_DEF_MODE (PCF_WARN_UNUSED_DEPRECATED)
extern void pcf_free_master_entry(PCF_MASTER_ENT *);
extern void pcf_show_master_fields(VSTREAM *, int, int, char **);
extern void pcf_edit_master_field(PCF_MASTER_ENT *, int, const char *);
-extern void pcf_show_master_params(VSTREAM *, int, int, char **);
+extern void pcf_show_master_params(VSTREAM *, int, int, int, char **);
extern void pcf_edit_master_param(PCF_MASTER_ENT *, int, const char *, const char *);
#define PCF_WARN_ON_OPEN_ERROR 0
(PCF_PARAM_NODE *) 0));
}
+/* pcf_dont_parse_parameter_value - disable recursion for raw parameters */
+
+static bool pcf_dont_parse_parameter_value(const char *key, void *unused_context)
+{
+ PCF_PARAM_NODE *node;
+
+ /* Only built-in parameters can be 'raw'. No need to inspect local_scope. */
+ return ((node = PCF_PARAM_TABLE_FIND(pcf_param_table, key)) != 0
+ && PCF_RAW_PARAMETER(node));
+}
+
/* pcf_expand_parameter_value - expand $name in parameter value */
char *pcf_expand_parameter_value(VSTRING *buf, int mode, const char *value,
eval_ctx.mode = (mode & ~PCF_SHOW_NONDEF);
eval_ctx.local_scope = local_scope;
- status = mac_expand(buf, value, MAC_EXP_FLAG_RECURSE, DONT_FILTER,
- pcf_lookup_parameter_value_wrapper, (void *) &eval_ctx);
+ status = mac_expand7(buf, value, MAC_EXP_FLAG_RECURSE, DONT_FILTER,
+ pcf_lookup_parameter_value_wrapper,
+ pcf_dont_parse_parameter_value, (void *) &eval_ctx);
if (status & MAC_PARSE_ERROR)
msg_fatal("macro processing error");
if (msg_verbose > 1) {
/* int field;
/* const char *new_value;
/*
-/* void pcf_show_master_params(fp, mode, argc, **param_filters)
+/* void pcf_show_master_params(fp, mode, param_class, argc, **param_filters)
/* VSTREAM *fp;
/* int mode;
+/* int param_class;
/* int argc;
/* char **param_filters;
/*
/* or multi-column attribute.
/*
/* pcf_show_master_params() writes name/type/parameter=value
-/* records to the specified stream.
+/* records to the specified stream. Like show_parameters(),
+/* this may list either selected parameters, or all parameters that
+/* match the param_class argument.
/*
/* pcf_edit_master_param() updates, removes or adds the named
/* parameter in a master.cf entry (the remove request ignores
return (strcmp(*(char **) a, *(char **) b));
}
+/* merge_main_master_parameters - all parameters as sen by this service */
+
+static DICT *merge_main_master_parameters(int mode, PCF_MASTER_ENT *masterp,
+ int param_class)
+{
+ DICT *dict;
+ PCF_PARAM_INFO **main_list;
+ PCF_PARAM_INFO **main_ht;
+ const char *dict_spec = "merged_dict";
+ const char *param_name;
+ const char *param_value;
+ int how;
+
+ /*
+ * With -PP, use the merged main/master.cf settings instead of
+ * masterp->allparams (the master.cf settings for this service).
+ */
+ dict = dict_ht_open(dict_spec, O_CREAT | O_RDWR, 0);
+ dict_register(dict_spec, dict);
+
+ /*
+ * For each parameter in the main.cf namespace, look up its effective
+ * value (from master.cf or main.cf, or use the default).
+ */
+ main_list = PCF_PARAM_TABLE_LIST(pcf_param_table);
+ for (main_ht = main_list; *main_ht; main_ht++) {
+ param_name = PCF_PARAM_INFO_NAME(*main_ht);
+ if (param_class && !(PCF_PARAM_INFO_NODE(*main_ht)->flags & param_class))
+ continue;
+ if ((param_value =
+ pcf_lookup_parameter_value(mode, param_name, masterp,
+ PCF_PARAM_INFO_NODE(*main_ht))) == 0)
+ msg_panic("%s: parameter name not found: %s", __func__, param_name);
+ dict->update(dict, param_name, param_value);
+ }
+ myfree((void *) main_list);
+
+ /*
+ * Add master.cf settings with service-specific custom names. Skip
+ * settings that were already copied in the above loop.
+ */
+ if (masterp->all_params) {
+ DICT *all_params = masterp->all_params;
+
+ for (how = DICT_SEQ_FUN_FIRST;
+ all_params->sequence(all_params, how, ¶m_name,
+ ¶m_value) == 0;
+ how = DICT_SEQ_FUN_NEXT) {
+ if (dict->lookup(dict, param_name) == 0)
+ dict->update(dict, param_name, param_value);
+ }
+ }
+ return (dict);
+}
+
/* pcf_show_master_any_param - show any parameter in master.cf service entry */
static void pcf_show_master_any_param(VSTREAM *fp, int mode,
- PCF_MASTER_ENT *masterp)
+ PCF_MASTER_ENT *masterp,
+ DICT *dict)
{
const char *myname = "pcf_show_master_any_param";
ARGV *argv = argv_alloc(10);
- DICT *dict = masterp->all_params;
const char *param_name;
const char *param_value;
int param_count = 0;
/* pcf_show_master_params - show master.cf params */
-void pcf_show_master_params(VSTREAM *fp, int mode, int argc, char **argv)
+void pcf_show_master_params(VSTREAM *fp, int mode, int param_class,
+ int argc, char **argv)
{
PCF_MASTER_ENT *masterp;
PCF_MASTER_FLD_REQ *field_reqs;
* Iterate over the master table.
*/
for (masterp = pcf_master_table; masterp->argv != 0; masterp++) {
- if ((dict = masterp->all_params) != 0) {
+ if (mode & PCF_MASTER_PP) {
+ dict = merge_main_master_parameters(mode, masterp,
+ argc > 0 ? 0 : param_class);
+ } else {
+ dict = masterp->all_params;
+ }
+ if (dict != 0) {
if (argc > 0) {
for (req = field_reqs; req < field_reqs + argc; req++) {
if (PCF_MATCH_SERVICE_PATTERN(req->service_pattern,
masterp->argv->argv[0],
masterp->argv->argv[1])) {
if (PCF_IS_MAGIC_PARAM_PATTERN(req->param_pattern)) {
- pcf_show_master_any_param(fp, mode, masterp);
+ pcf_show_master_any_param(fp, mode, masterp, dict);
req->match_count += 1;
} else if ((param_value = dict_get(dict,
req->param_pattern)) != 0) {
}
}
} else {
- pcf_show_master_any_param(fp, mode, masterp);
+ pcf_show_master_any_param(fp, mode, masterp, dict);
}
}
+ if (mode & PCF_MASTER_PP)
+ dict_close(dict);
}
/*
PCF_PARAM_CTX _ctx; \
_ctx.local_scope = (scope); \
_ctx.param_class = (class); \
+ /* No MAC_EXP_FLAG_RECURSE, therefore no need for DONT_PARSE feature. */ \
(void) mac_expand(NO_SCAN_RESULT, (value), MAC_EXP_FLAG_SCAN, \
NO_SCAN_FILTER, pcf_flag_user_parameter_wrapper, (void *) &_ctx); \
} while (0)
--- /dev/null
+foo/unix/proxy_write_maps = foo_map
+bar/unix/proxy_write_maps = bar_map
+baz/unix/proxy_write_maps = baz_map
/* SYNOPSIS
/* #include <mac_expand.h>
/*
-/* int mac_expand(result, pattern, flags, filter, lookup, context)
+/* int mac_expand7(result, pattern, flags, filter, lookup,
+/* dont_expand, context)
/* VSTRING *result;
/* const char *pattern;
/* int flags;
/* const char *filter;
/* const char *lookup(const char *key, int mode, void *context)
+/* const bool dont_parse(const char *key, void *context)
/* void *context;
/* AUXILIARY FUNCTIONS
+/* int mac_expand(result, pattern, flags, filter, lookup, context)
+/* VSTRING *result;
+/* const char *pattern;
+/* int flags;
+/* const char *filter;
+/* const char *lookup(const char *key, int mode, void *context)
+/* void *context;
+/*
/* typedef MAC_EXP_OP_RES (*MAC_EXPAND_RELOP_FN) (
/* const char *left,
/* int tok_val,
/* or MAC_EXP_MODE_USE to use the value of the named attribute,
/* and the caller context that was given to mac_expand(). A null
/* result value means that the requested attribute was not defined.
+/* .IP don_parse
+/* An optional function that disables the MAC_EXP_FLAG_RECURSE
+/* feature with lookup() results for a specific attribute. Arguments
+/* are: the attribute name, and the caller context that was given
+/* to mac_expand(). Specify null to disable this feature.
/* .IP context
-/* Caller context that is passed on to the attribute lookup routine.
+/* Caller context that is passed on to the attribute lookup and
+/* don_parse routines.
/* .PP
/* mac_expand_add_relop() registers a function that implements
/* support for custom relational operators. Custom operator names
int flags; /* features */
const char *filter; /* character filter */
MAC_EXP_LOOKUP_FN lookup; /* lookup routine */
+ MAC_EXP_DONT_PARSE_FN dont_parse; /* veto routine */
void *context; /* caller context */
int status; /* findings */
int level; /* nesting level */
ssize_t tmp_len;
const char *res_iftrue;
const char *res_iffalse;
+ int dont_parse = false;
/*
* Sanity check.
* Look up the named parameter. Todo: allow the lookup function
* to specify if the result is safe for $name expansion.
*/
+ if (mc->dont_parse)
+ dont_parse = mc->dont_parse(start, mc->context);
lookup = mc->lookup(start, lookup_mode, mc->context);
}
mc->status |= MAC_PARSE_UNDEF;
} else if (*lookup == 0 || (mc->flags & MAC_EXP_FLAG_SCAN)) {
/* void */ ;
- } else if (mc->flags & MAC_EXP_FLAG_RECURSE) {
+ } else if ((mc->flags & MAC_EXP_FLAG_RECURSE) && !dont_parse) {
vstring_strcpy(buf, lookup);
mc->status |= mac_parse(vstring_str(buf), mac_expand_callback,
(void *) mc);
return (mc->status);
}
+ /*
+ * ABI compatibility wrapper.
+ */
+#undef mac_expand
+int mac_expand(VSTRING *, const char *, int, const char *,
+ MAC_EXP_LOOKUP_FN, void *);
+
/* mac_expand - expand $name instances */
int mac_expand(VSTRING *result, const char *pattern, int flags,
const char *filter,
MAC_EXP_LOOKUP_FN lookup, void *context)
{
+ return (mac_expand7(result, pattern, flags, filter, lookup,
+ (MAC_EXP_DONT_PARSE_FN) 0, context));
+}
+
+int mac_expand7(VSTRING *result, const char *pattern, int flags,
+ const char *filter,
+ MAC_EXP_LOOKUP_FN lookup,
+ MAC_EXP_DONT_PARSE_FN dont_parse, void *context)
+{
+
MAC_EXP_CONTEXT mc;
int status;
mc.flags = flags;
mc.filter = filter;
mc.lookup = lookup;
+ mc.dont_parse = dont_parse;
mc.context = context;
mc.status = 0;
mc.level = 0;
#define MAC_EXP_MODE_USE (1)
typedef const char *(*MAC_EXP_LOOKUP_FN) (const char *, int, void *);
+typedef bool(*MAC_EXP_DONT_PARSE_FN) (const char *, void *);
typedef MAC_EXP_OP_RES(*MAC_EXPAND_RELOP_FN) (const char *, int, const char *);
typedef int (*MAC_EXPAND_NAMED_FN) (VSTRING *, const char *);
-extern int mac_expand(VSTRING *, const char *, int, const char *, MAC_EXP_LOOKUP_FN, void *);
+extern int mac_expand7(VSTRING *, const char *, int, const char *, MAC_EXP_LOOKUP_FN, MAC_EXP_DONT_PARSE_FN, void *);
extern void mac_expand_add_relop(int *, const char *, MAC_EXPAND_RELOP_FN);
extern void mac_expand_add_named_fn(const char *, MAC_EXPAND_NAMED_FN);
+#define mac_expand(res, pat, flags, filter, lookup, ctx) \
+ mac_expand7((res), (pat), (flags), (filter), (lookup), \
+ (MAC_EXP_DONT_PARSE_FN) 0, (ctx))
+
/* LICENSE
/* .ad
/* .fi