mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-03 15:45:24 +00:00
snapshot-19991209
This commit is contained in:
@@ -25,8 +25,8 @@ Append one or more -v options to selected daemon definitions in
|
|||||||
/etc/postfix/master.cf and type "postfix reload". This will cause
|
/etc/postfix/master.cf and type "postfix reload". This will cause
|
||||||
a lot of activity to be logged to the syslog daemon.
|
a lot of activity to be logged to the syslog daemon.
|
||||||
|
|
||||||
4 - Tracing a Postfix daemon process
|
4 - Manually tracing a Postfix daemon process
|
||||||
====================================
|
=============================================
|
||||||
|
|
||||||
Some systems allow you to inspect a running process with a system
|
Some systems allow you to inspect a running process with a system
|
||||||
call tracer. For example:
|
call tracer. For example:
|
||||||
@@ -41,12 +41,30 @@ See your system documentation for details.
|
|||||||
Tracing a running process can give valuable information about what
|
Tracing a running process can give valuable information about what
|
||||||
a process is attempting to do. This is as much information as you
|
a process is attempting to do. This is as much information as you
|
||||||
can get without running an interactive debugger program, as described
|
can get without running an interactive debugger program, as described
|
||||||
in the next section.
|
in a later section.
|
||||||
|
|
||||||
See the next section on how to automatically attach a program to
|
5 - Automatically tracing a Postfix daemon process
|
||||||
a Postfix daemon.
|
==================================================
|
||||||
|
|
||||||
5 - Running daemon programs under an interactive debugger
|
Postfix can attach a call tracer whenever a daemon process starts.
|
||||||
|
|
||||||
|
Append a -D option to the suspect command in /etc/postfix/master.cf,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
smtp inet n - n - - smtpd -D
|
||||||
|
|
||||||
|
Edit the debugger_command definition in /etc/postfix/main.cf so
|
||||||
|
that it invokes the call tracer of your choice, for example:
|
||||||
|
|
||||||
|
debugger_command =
|
||||||
|
PATH=/bin:/usr/bin:/usr/local/bin
|
||||||
|
(truss -p $process_id 2>&1 | logger -p mail.info) & sleep 5
|
||||||
|
|
||||||
|
Instead of truss use trace or strace.
|
||||||
|
|
||||||
|
Type "postfix reload" and watch the logfile.
|
||||||
|
|
||||||
|
6 - Running daemon programs under an interactive debugger
|
||||||
=========================================================
|
=========================================================
|
||||||
|
|
||||||
Append a -D option to the suspect command in /etc/postfix/master.cf,
|
Append a -D option to the suspect command in /etc/postfix/master.cf,
|
||||||
@@ -72,7 +90,7 @@ Stop and start the Postfix system.
|
|||||||
Whenever the suspect daemon process is started, a debugger window
|
Whenever the suspect daemon process is started, a debugger window
|
||||||
pops up and you can watch in detail what happens.
|
pops up and you can watch in detail what happens.
|
||||||
|
|
||||||
6 - Unreasonable behavior
|
7 - Unreasonable behavior
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
Sometimes the behavior exhibit by Postfix just does not match the
|
Sometimes the behavior exhibit by Postfix just does not match the
|
||||||
|
@@ -3317,15 +3317,43 @@ Apologies for any names omitted.
|
|||||||
|
|
||||||
19991207
|
19991207
|
||||||
|
|
||||||
Performance: the queue manager now frees in-memory recipients
|
Performance: one message with many recipients no longer
|
||||||
as soon as a message is delivered to one destination, rather
|
stops other mail from being delivered. The queue manager
|
||||||
than waiting until all in-memory recipients of that message
|
now frees in-memory recipients as soon as a message is
|
||||||
have been tried. This means that one message with many
|
delivered to one destination, rather than waiting until
|
||||||
recipients no longer stops other mail from being delivered.
|
all in-memory destinations of that message have been tried.
|
||||||
Patch by Patrik Rak @ ein.cz. Files: qmgr/qmgr_entry.c,
|
Patch by Patrik Rak @ ein.cz. Files: qmgr/qmgr_entry.c,
|
||||||
qmgr/qmgr_message.c.
|
qmgr/qmgr_message.c.
|
||||||
|
|
||||||
Performance: when delivering a huge list of recipients,
|
Performance: when delivering mail to a huge list of
|
||||||
the queue manager now reads new recipients from queue file
|
recipients, the queue manager now reads more recipients
|
||||||
before delivery concurrency starts dropping. Files:
|
from the queue file before delivery concurrency starts
|
||||||
qmgr/qmgr_entry.c, qmgr/qmgr_message.c.
|
to drop. Files: qmgr/qmgr_entry.c, qmgr/qmgr_message.c.
|
||||||
|
|
||||||
|
19991208
|
||||||
|
|
||||||
|
Performance: improved worst-case behavior. A fully loaded
|
||||||
|
Postfix inflicts the same delay to messages with any number
|
||||||
|
of recipients (up to qmgr_message_recipient_limit.) Inspired
|
||||||
|
by discussions with Patrik Rak (although he disagrees with
|
||||||
|
the strategy). File: qmgr/qmgr_message.c.
|
||||||
|
|
||||||
|
Updated LDAP client code by John Hensley with escape
|
||||||
|
sequences as per RFC 2254. File: util/dict_ldap.c.
|
||||||
|
|
||||||
|
Updated MYSQL client code by Scott Cotton. File: dict_mysql.c.
|
||||||
|
|
||||||
|
Feature: added -N/-n options to include/exclude terminating
|
||||||
|
nulls in keys and values in postmap/postalias DB or DBM
|
||||||
|
files. Normally, Postfix uses whatever is appropriate for
|
||||||
|
the host system. A non-default setting can be necessary
|
||||||
|
for inter-operability with third-party software.
|
||||||
|
|
||||||
|
Bugfix: the local delivery agent would deliver to the user
|
||||||
|
instead of the .forward file when the .forward file was
|
||||||
|
already visited via some non-recursive path. Patch by Patrik
|
||||||
|
Rak @ ein.cz. Files: global/been_here.c, local/dotforward.c.
|
||||||
|
|
||||||
|
Robustness: attempt to deliver all addresses in the expansion
|
||||||
|
of an alias or .forward file, even when some addresses must
|
||||||
|
be deferred. File: local/token.c.
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
Incompatible changes with snapshot 19991127
|
Incompatible changes with snapshot 19991209
|
||||||
===========================================
|
===========================================
|
||||||
|
|
||||||
- In an SMTPD access map, an all-numeric right-hand side now means
|
- In an SMTPD access map, an all-numeric right-hand side now means
|
||||||
@@ -18,7 +18,7 @@ $mydestination domains matches a transport specification, you also
|
|||||||
need to add a "domain.name local:" entry in your transport_maps.
|
need to add a "domain.name local:" entry in your transport_maps.
|
||||||
See the html/faq.html sections for firewalls and intranets.
|
See the html/faq.html sections for firewalls and intranets.
|
||||||
|
|
||||||
Major changes with snapshot 19991127
|
Major changes with snapshot 19991209
|
||||||
====================================
|
====================================
|
||||||
|
|
||||||
- It is now relatively safe to configure 550 status codes for the
|
- It is now relatively safe to configure 550 status codes for the
|
||||||
|
@@ -222,9 +222,9 @@ mail_owner = postfix
|
|||||||
# DELIVERY TO MAILBOX
|
# DELIVERY TO MAILBOX
|
||||||
#
|
#
|
||||||
# The home_mailbox parameter specifies the optional pathname of a
|
# The home_mailbox parameter specifies the optional pathname of a
|
||||||
# mailbox relative to a user's home directory. The default is to
|
# mailbox file relative to a user's home directory. The default
|
||||||
# deliver to the UNIX-style /var/spool/mail/user or /var/mail/user.
|
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
|
||||||
# Specify "Maildir/" for qmail-style delivery (the / is required).
|
# "Maildir/" for qmail-style delivery (the / is required).
|
||||||
#
|
#
|
||||||
#home_mailbox = Mailbox
|
#home_mailbox = Mailbox
|
||||||
#home_mailbox = Maildir/
|
#home_mailbox = Maildir/
|
||||||
@@ -298,12 +298,14 @@ mail_owner = postfix
|
|||||||
#header_checks = regexp:/etc/postfix/filename
|
#header_checks = regexp:/etc/postfix/filename
|
||||||
#header_checks = pcre:/etc/postfix/filename
|
#header_checks = pcre:/etc/postfix/filename
|
||||||
|
|
||||||
# The relay_domains parameter restricts what domains (and subdomains
|
# The relay_domains parameter restricts what client hostname domains
|
||||||
# thereof) this mail system will relay mail from or to. See the
|
# (and subdomains thereof) this mail system will relay mail from,
|
||||||
# smtpd_recipient_restrictions restriction in the file sample-smtpd.cf.
|
# and restricts what destination domains (and subdomains thereof)
|
||||||
|
# this system will relay mail to. See the smtpd_recipient_restrictions
|
||||||
|
# restriction in the file sample-smtpd.cf.
|
||||||
#
|
#
|
||||||
# By default, Postfix relays mail only from or to sites in or below
|
# By default, Postfix relays mail only from clients or to destinations
|
||||||
# $mydestination, or in the optional virtual domain list.
|
# in or below $mydestination, or in the optional virtual domain list.
|
||||||
#
|
#
|
||||||
# Specify a list of hosts or domains, /file/name patterns or type:name
|
# Specify a list of hosts or domains, /file/name patterns or type:name
|
||||||
# lookup tables, separated by commas and/or whitespace. Continue
|
# lookup tables, separated by commas and/or whitespace. Continue
|
||||||
|
@@ -66,9 +66,9 @@ default_privs = nobody
|
|||||||
#
|
#
|
||||||
|
|
||||||
# The home_mailbox parameter specifies the optional pathname of a
|
# The home_mailbox parameter specifies the optional pathname of a
|
||||||
# mailbox relative to a user's home directory. The default is to
|
# mailbox file relative to a user's home directory. The default
|
||||||
# deliver to the UNIX-style /var/spool/mail/user or /var/mail/user.
|
# mailbox file is /var/spool/mail/user or /var/mail/user. Specify
|
||||||
# Specify "Maildir/" for qmail-style delivery (the / is required).
|
# "Maildir/" for qmail-style delivery (the / is required).
|
||||||
#
|
#
|
||||||
# home_mailbox = Mailbox
|
# home_mailbox = Mailbox
|
||||||
# home_mailbox = Maildir/
|
# home_mailbox = Maildir/
|
||||||
|
@@ -181,7 +181,7 @@ smtpd_sender_restrictions =
|
|||||||
#
|
#
|
||||||
# The default is to permit any destination from clients that match
|
# The default is to permit any destination from clients that match
|
||||||
# $mynetworks, and to otherwise permit only mail from clients or to
|
# $mynetworks, and to otherwise permit only mail from clients or to
|
||||||
# domains that match $relay_domains or a subdomain thereof.
|
# destinations that match $relay_domains or a subdomain thereof.
|
||||||
#
|
#
|
||||||
# The following restrictions are available:
|
# The following restrictions are available:
|
||||||
#
|
#
|
||||||
@@ -191,8 +191,8 @@ smtpd_sender_restrictions =
|
|||||||
# reject_invalid_hostname: reject HELO hostname with bad syntax.
|
# reject_invalid_hostname: reject HELO hostname with bad syntax.
|
||||||
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
|
# reject_unknown_hostname: reject HELO hostname without DNS A or MX record.
|
||||||
# reject_unknown_sender_domain: reject sender domain without A or MX record.
|
# reject_unknown_sender_domain: reject sender domain without A or MX record.
|
||||||
# check_relay_domains: permit only mail from/to domains in $relay_domains
|
# check_relay_domains: permit only mail from clients/to domains matching
|
||||||
or to the local machine.
|
# $relay_domains, or to the local machine.
|
||||||
# permit_auth_destination: permit mail to self or to $relay_domains.
|
# permit_auth_destination: permit mail to self or to $relay_domains.
|
||||||
# reject_unauth_destination: reject mail not to self or to $relay_domains.
|
# reject_unauth_destination: reject mail not to self or to $relay_domains.
|
||||||
# reject_unauth_pipelining: reject mail from improperly pipelining spamware
|
# reject_unauth_pipelining: reject mail from improperly pipelining spamware
|
||||||
@@ -238,11 +238,13 @@ smtpd_recipient_restrictions = permit_mynetworks,check_relay_domains
|
|||||||
#
|
#
|
||||||
maps_rbl_domains = rbl.maps.vix.com
|
maps_rbl_domains = rbl.maps.vix.com
|
||||||
|
|
||||||
# The relay_domains parameter restricts what domains (and subdomains
|
# The relay_domains parameter restricts what client hostname domains
|
||||||
# thereof) this mail system will relay mail from or to.
|
# (and subdomains thereof) this mail system will relay mail from,
|
||||||
|
# and restricts what destination domains (and subdomains thereof)
|
||||||
|
# this system will relay mail to.
|
||||||
#
|
#
|
||||||
# By default, Postfix relays mail only from or to sites in or below
|
# By default, Postfix relays mail only from clients or to destinations
|
||||||
# $mydestination, or in the optional virtual domain list.
|
# in or below $mydestination, or in the optional virtual domain list.
|
||||||
#
|
#
|
||||||
# Specify a list of hosts or domains, /file/name patterns or type:name
|
# Specify a list of hosts or domains, /file/name patterns or type:name
|
||||||
# lookup tables, separated by commas and/or whitespace. Continue
|
# lookup tables, separated by commas and/or whitespace. Continue
|
||||||
|
@@ -17,6 +17,14 @@
|
|||||||
/* BH_TABLE *dup_filter;
|
/* BH_TABLE *dup_filter;
|
||||||
/* char *format;
|
/* char *format;
|
||||||
/*
|
/*
|
||||||
|
/* int been_here_check_fixed(dup_filter, string)
|
||||||
|
/* BH_TABLE *dup_filter;
|
||||||
|
/* char *string;
|
||||||
|
/*
|
||||||
|
/* int been_here_check(dup_filter, format, ...)
|
||||||
|
/* BH_TABLE *dup_filter;
|
||||||
|
/* char *format;
|
||||||
|
/*
|
||||||
/* void been_here_free(dup_filter)
|
/* void been_here_free(dup_filter)
|
||||||
/* BH_TABLE *dup_filter;
|
/* BH_TABLE *dup_filter;
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
@@ -34,6 +42,9 @@
|
|||||||
/* not found. The result is non-zero (true) if the formatted result was
|
/* not found. The result is non-zero (true) if the formatted result was
|
||||||
/* found, zero (false) otherwise.
|
/* found, zero (false) otherwise.
|
||||||
/*
|
/*
|
||||||
|
/* been_here_check_fixed() and been_here_check() are similar
|
||||||
|
/* but do not update the duplicate filter.
|
||||||
|
/*
|
||||||
/* been_here_free() releases storage for a duplicate filter.
|
/* been_here_free() releases storage for a duplicate filter.
|
||||||
/*
|
/*
|
||||||
/* Arguments:
|
/* Arguments:
|
||||||
@@ -173,3 +184,65 @@ int been_here_fixed(BH_TABLE *dup_filter, const char *string)
|
|||||||
|
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* been_here_check - query duplicate detector with finer control */
|
||||||
|
|
||||||
|
int been_here_check(BH_TABLE *dup_filter, const char *fmt,...)
|
||||||
|
{
|
||||||
|
VSTRING *buf = vstring_alloc(100);
|
||||||
|
int status;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Construct the string to be checked.
|
||||||
|
*/
|
||||||
|
va_start(ap, fmt);
|
||||||
|
vstring_vsprintf(buf, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do the duplicate check.
|
||||||
|
*/
|
||||||
|
status = been_here_check_fixed(dup_filter, vstring_str(buf));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup.
|
||||||
|
*/
|
||||||
|
vstring_free(buf);
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* been_here_check_fixed - query duplicate detector */
|
||||||
|
|
||||||
|
int been_here_check_fixed(BH_TABLE *dup_filter, const char *string)
|
||||||
|
{
|
||||||
|
char *folded_string;
|
||||||
|
const char *lookup_key;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Special processing: case insensitive lookup.
|
||||||
|
*/
|
||||||
|
if (dup_filter->flags & BH_FLAG_FOLD) {
|
||||||
|
folded_string = mystrdup(string);
|
||||||
|
lookup_key = lowercase(folded_string);
|
||||||
|
} else {
|
||||||
|
folded_string = 0;
|
||||||
|
lookup_key = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do the duplicate check.
|
||||||
|
*/
|
||||||
|
status = (htable_locate(dup_filter->table, lookup_key) != 0);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("been_here_check: %s: %d", string, status);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cleanup.
|
||||||
|
*/
|
||||||
|
if (folded_string)
|
||||||
|
myfree(folded_string);
|
||||||
|
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
@@ -32,6 +32,8 @@ extern BH_TABLE *been_here_init(int, int);
|
|||||||
extern void been_here_free(BH_TABLE *);
|
extern void been_here_free(BH_TABLE *);
|
||||||
extern int been_here_fixed(BH_TABLE *, const char *);
|
extern int been_here_fixed(BH_TABLE *, const char *);
|
||||||
extern int been_here(BH_TABLE *, const char *,...);
|
extern int been_here(BH_TABLE *, const char *,...);
|
||||||
|
extern int been_here_check_fixed(BH_TABLE *, const char *);
|
||||||
|
extern int been_here_check(BH_TABLE *, const char *,...);
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-19991207"
|
#define DEF_MAIL_VERSION "Snapshot-19991209"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -9,7 +9,7 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
postalias - Postfix alias database maintenance
|
postalias - Postfix alias database maintenance
|
||||||
|
|
||||||
<b>SYNOPSIS</b>
|
<b>SYNOPSIS</b>
|
||||||
<b>postalias</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
<b>postalias</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||||
[<i>file_type</i>:]<i>file_name</i> ...
|
[<i>file_type</i>:]<i>file_name</i> ...
|
||||||
|
|
||||||
<b>DESCRIPTION</b>
|
<b>DESCRIPTION</b>
|
||||||
@@ -26,15 +26,25 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
|
<b>-N</b> Include the terminating null character that termi-
|
||||||
|
nates lookup keys and values. By default, Postfix
|
||||||
|
does whatever is the default for the host operating
|
||||||
|
system.
|
||||||
|
|
||||||
<b>-c</b> <i>config_dir</i>
|
<b>-c</b> <i>config_dir</i>
|
||||||
Read the <b>main.cf</b> configuration file in the named
|
Read the <b>main.cf</b> configuration file in the named
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
<b>-i</b> Incremental mode. Read entries from standard input
|
<b>-i</b> Incremental mode. Read entries from standard input
|
||||||
and do not truncate an existing database. By
|
and do not truncate an existing database. By
|
||||||
default, <b>postalias</b> creates a new database from the
|
default, <b>postalias</b> creates a new database from the
|
||||||
entries in <b>file</b><i>_</i><b>name</b>.
|
entries in <b>file</b><i>_</i><b>name</b>.
|
||||||
|
|
||||||
|
<b>-n</b> Don't include the terminating null character that
|
||||||
|
terminates lookup keys and values. By default,
|
||||||
|
Postfix does whatever is the default for the host
|
||||||
|
operating system.
|
||||||
|
|
||||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
||||||
first value found on the standard output stream.
|
first value found on the standard output stream.
|
||||||
The exit status is non-zero if the requested infor-
|
The exit status is non-zero if the requested infor-
|
||||||
@@ -49,16 +59,6 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
|
|
||||||
<i>file_type</i>
|
|
||||||
The type of database to be produced.
|
|
||||||
|
|
||||||
<b>btree</b> The output is a btree file, named
|
|
||||||
<i>file_name</i><b>.db</b>. This is available only on
|
|
||||||
systems with support for <b>db</b> databases.
|
|
||||||
|
|
||||||
<b>dbm</b> The output consists of two files, named
|
|
||||||
<i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
|
|
||||||
available only on systems with support for
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -71,6 +71,16 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
POSTALIAS(1) POSTALIAS(1)
|
POSTALIAS(1) POSTALIAS(1)
|
||||||
|
|
||||||
|
|
||||||
|
<i>file_type</i>
|
||||||
|
The type of database to be produced.
|
||||||
|
|
||||||
|
<b>btree</b> The output is a btree file, named
|
||||||
|
<i>file_name</i><b>.db</b>. This is available only on
|
||||||
|
systems with support for <b>db</b> databases.
|
||||||
|
|
||||||
|
<b>dbm</b> The output consists of two files, named
|
||||||
|
<i>file_name</i><b>.pag</b> and <i>file_name</i><b>.dir</b>. This is
|
||||||
|
available only on systems with support for
|
||||||
<b>dbm</b> databases.
|
<b>dbm</b> databases.
|
||||||
|
|
||||||
<b>hash</b> The output is a hashed file, named
|
<b>hash</b> The output is a hashed file, named
|
||||||
@@ -114,6 +124,19 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
<a href="aliases.5.html">aliases(5)</a> format of alias database input file.
|
<a href="aliases.5.html">aliases(5)</a> format of alias database input file.
|
||||||
<a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
|
<a href="sendmail.1.html">sendmail(1)</a> mail posting and compatibility interface.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
POSTALIAS(1) POSTALIAS(1)
|
||||||
|
|
||||||
|
|
||||||
<b>LICENSE</b>
|
<b>LICENSE</b>
|
||||||
The Secure Mailer license must be distributed with this
|
The Secure Mailer license must be distributed with this
|
||||||
software.
|
software.
|
||||||
@@ -128,7 +151,50 @@ POSTALIAS(1) POSTALIAS(1)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
2
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
3
|
||||||
|
|
||||||
|
|
||||||
</pre> </body> </html>
|
</pre> </body> </html>
|
||||||
|
@@ -9,7 +9,7 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
postmap - Postfix lookup table management
|
postmap - Postfix lookup table management
|
||||||
|
|
||||||
<b>SYNOPSIS</b>
|
<b>SYNOPSIS</b>
|
||||||
<b>postmap</b> [<b>-ivw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
<b>postmap</b> [<b>-Ninvw</b>] [<b>-c</b> <i>config_dir</i>] [<b>-q</b> <i>key</i>]
|
||||||
[<i>file_type</i>:]<i>file_name</i> ...
|
[<i>file_type</i>:]<i>file_name</i> ...
|
||||||
|
|
||||||
<b>DESCRIPTION</b>
|
<b>DESCRIPTION</b>
|
||||||
@@ -45,20 +45,20 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
|
<b>-N</b> Include the terminating null character that termi-
|
||||||
|
nates lookup keys and values. By default, Postfix
|
||||||
|
does whatever is the default for the host operating
|
||||||
|
system.
|
||||||
|
|
||||||
<b>-c</b> <i>config_dir</i>
|
<b>-c</b> <i>config_dir</i>
|
||||||
Read the <b>main.cf</b> configuration file in the named
|
Read the <b>main.cf</b> configuration file in the named
|
||||||
directory.
|
directory.
|
||||||
|
|
||||||
<b>-i</b> Incremental mode. Read entries from standard input
|
<b>-i</b> Incremental mode. Read entries from standard input
|
||||||
and do not truncate an existing database. By
|
and do not truncate an existing database. By
|
||||||
default, <b>postmap</b> creates a new database from the
|
default, <b>postmap</b> creates a new database from the
|
||||||
entries in <b>file</b><i>_</i><b>name</b>.
|
entries in <b>file</b><i>_</i><b>name</b>.
|
||||||
|
|
||||||
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
|
||||||
first value found on the standard output stream.
|
|
||||||
The exit status is non-zero if the requested infor-
|
|
||||||
mation was not found.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -71,6 +71,16 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
POSTMAP(1) POSTMAP(1)
|
POSTMAP(1) POSTMAP(1)
|
||||||
|
|
||||||
|
|
||||||
|
<b>-n</b> Don't include the terminating null character that
|
||||||
|
terminates lookup keys and values. By default,
|
||||||
|
Postfix does whatever is the default for the host
|
||||||
|
operating system.
|
||||||
|
|
||||||
|
<b>-q</b> <i>key</i> Search the specified maps for <i>key</i> and print the
|
||||||
|
first value found on the standard output stream.
|
||||||
|
The exit status is non-zero if the requested infor-
|
||||||
|
mation was not found.
|
||||||
|
|
||||||
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
|
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
|
||||||
tiple <b>-v</b> options make the software increasingly
|
tiple <b>-v</b> options make the software increasingly
|
||||||
verbose.
|
verbose.
|
||||||
@@ -116,16 +126,6 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
<b>MAIL</b><i>_</i><b>VERBOSE</b>
|
<b>MAIL</b><i>_</i><b>VERBOSE</b>
|
||||||
Enable verbose logging for debugging purposes.
|
Enable verbose logging for debugging purposes.
|
||||||
|
|
||||||
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
|
||||||
<b>database</b><i>_</i><b>type</b>
|
|
||||||
Default output database type. On many UNIX sys-
|
|
||||||
tems, the default database type is either <b>hash</b> or
|
|
||||||
<b>dbm</b>.
|
|
||||||
|
|
||||||
<b>LICENSE</b>
|
|
||||||
The Secure Mailer license must be distributed with this
|
|
||||||
software.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
2
|
2
|
||||||
@@ -137,6 +137,16 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
POSTMAP(1) POSTMAP(1)
|
POSTMAP(1) POSTMAP(1)
|
||||||
|
|
||||||
|
|
||||||
|
<b>CONFIGURATION</b> <b>PARAMETERS</b>
|
||||||
|
<b>database</b><i>_</i><b>type</b>
|
||||||
|
Default output database type. On many UNIX sys-
|
||||||
|
tems, the default database type is either <b>hash</b> or
|
||||||
|
<b>dbm</b>.
|
||||||
|
|
||||||
|
<b>LICENSE</b>
|
||||||
|
The Secure Mailer license must be distributed with this
|
||||||
|
software.
|
||||||
|
|
||||||
<b>AUTHOR(S)</b>
|
<b>AUTHOR(S)</b>
|
||||||
Wietse Venema
|
Wietse Venema
|
||||||
IBM T.J. Watson Research
|
IBM T.J. Watson Research
|
||||||
@@ -173,16 +183,6 @@ POSTMAP(1) POSTMAP(1)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@@ -550,7 +550,7 @@ specifies the response code for rejected requests (default:
|
|||||||
|
|
||||||
<dt> <b>permit_auth_destination</b> <dd> Ignore the client hostname.
|
<dt> <b>permit_auth_destination</b> <dd> Ignore the client hostname.
|
||||||
Permit the request when the resolved destination address matches
|
Permit the request when the resolved destination address matches
|
||||||
the <a href="basic.html#mydestination">$mydestination</a>, the
|
<a href="basic.html#mydestination">$mydestination</a>, the
|
||||||
machine IP addresses, or <a href="#relay_domains"> $relay_domains</a>.
|
machine IP addresses, or <a href="#relay_domains"> $relay_domains</a>.
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@@ -213,27 +213,31 @@ int deliver_dotforward(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
|
|||||||
* If this user includes (an alias of) herself in her own .forward file,
|
* If this user includes (an alias of) herself in her own .forward file,
|
||||||
* deliver to the user instead.
|
* deliver to the user instead.
|
||||||
*/
|
*/
|
||||||
if (lookup_status >= 0
|
if (lookup_status >= 0) {
|
||||||
&& been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
|
if (been_here(state.dup_filter, "forward %s", STR(path)) == 0) {
|
||||||
state.msg_attr.exp_from = state.msg_attr.local;
|
state.msg_attr.exp_from = state.msg_attr.local;
|
||||||
if (S_ISREG(st.st_mode) == 0) {
|
if (S_ISREG(st.st_mode) == 0) {
|
||||||
msg_warn("file %s is not a regular file", STR(path));
|
msg_warn("file %s is not a regular file", STR(path));
|
||||||
} else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
|
} else if (st.st_uid != 0 && st.st_uid != usr_attr.uid) {
|
||||||
msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
|
msg_warn("file %s has bad owner uid %d", STR(path), st.st_uid);
|
||||||
} else if (st.st_mode & 002) {
|
} else if (st.st_mode & 002) {
|
||||||
msg_warn("file %s is world writable", STR(path));
|
msg_warn("file %s is world writable", STR(path));
|
||||||
} else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
|
} else if ((fd = open_as(STR(path), O_RDONLY, 0, usr_attr.uid, usr_attr.gid)) < 0) {
|
||||||
msg_warn("cannot open file %s: %m", STR(path));
|
msg_warn("cannot open file %s: %m", STR(path));
|
||||||
} else {
|
} else {
|
||||||
close_on_exec(fd, CLOSE_ON_EXEC);
|
close_on_exec(fd, CLOSE_ON_EXEC);
|
||||||
addr_count = 0;
|
addr_count = 0;
|
||||||
fp = vstream_fdopen(fd, O_RDONLY);
|
fp = vstream_fdopen(fd, O_RDONLY);
|
||||||
status = deliver_token_stream(state, usr_attr, fp, &addr_count);
|
status = deliver_token_stream(state, usr_attr, fp, &addr_count);
|
||||||
if (vstream_fclose(fp))
|
if (vstream_fclose(fp))
|
||||||
msg_warn("close file %s: %m", STR(path));
|
msg_warn("close file %s: %m", STR(path));
|
||||||
if (addr_count > 0)
|
if (addr_count > 0) {
|
||||||
forward_found = YES;
|
forward_found = YES;
|
||||||
}
|
been_here(state.dup_filter, "forward-done %s", STR(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (been_here_check(state.dup_filter, "forward-done %s", STR(path)) != 0)
|
||||||
|
forward_found = YES; /* else we're recursive */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -177,9 +177,7 @@ int deliver_token_string(LOCAL_STATE state, USER_ATTR usr_attr,
|
|||||||
if (addr->type == TOK822_ADDR) {
|
if (addr->type == TOK822_ADDR) {
|
||||||
if (addr_count)
|
if (addr_count)
|
||||||
(*addr_count)++;
|
(*addr_count)++;
|
||||||
status = deliver_token(state, usr_attr, addr);
|
status |= deliver_token(state, usr_attr, addr);
|
||||||
if (status != 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tok822_free_tree(tree);
|
tok822_free_tree(tree);
|
||||||
|
@@ -9,8 +9,8 @@ Postfix alias database maintenance
|
|||||||
.na
|
.na
|
||||||
.nf
|
.nf
|
||||||
.fi
|
.fi
|
||||||
\fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
\fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
|
||||||
[\fIfile_type\fR:]\fIfile_name\fR ...
|
[\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.ad
|
.ad
|
||||||
.fi
|
.fi
|
||||||
@@ -25,12 +25,20 @@ entire database, in order to avoid surprises in spectator
|
|||||||
programs.
|
programs.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
.IP \fB-N\fR
|
||||||
|
Include the terminating null character that terminates lookup keys
|
||||||
|
and values. By default, Postfix does whatever is the default for
|
||||||
|
the host operating system.
|
||||||
.IP "\fB-c \fIconfig_dir\fR"
|
.IP "\fB-c \fIconfig_dir\fR"
|
||||||
Read the \fBmain.cf\fR configuration file in the named directory.
|
Read the \fBmain.cf\fR configuration file in the named directory.
|
||||||
.IP \fB-i\fR
|
.IP \fB-i\fR
|
||||||
Incremental mode. Read entries from standard input and do not
|
Incremental mode. Read entries from standard input and do not
|
||||||
truncate an existing database. By default, \fBpostalias\fR creates
|
truncate an existing database. By default, \fBpostalias\fR creates
|
||||||
a new database from the entries in \fBfile_name\fR.
|
a new database from the entries in \fBfile_name\fR.
|
||||||
|
.IP \fB-n\fR
|
||||||
|
Don't include the terminating null character that terminates lookup
|
||||||
|
keys and values. By default, Postfix does whatever is the default for
|
||||||
|
the host operating system.
|
||||||
.IP "\fB-q \fIkey\fR"
|
.IP "\fB-q \fIkey\fR"
|
||||||
Search the specified maps for \fIkey\fR and print the first value
|
Search the specified maps for \fIkey\fR and print the first value
|
||||||
found on the standard output stream. The exit status is non-zero
|
found on the standard output stream. The exit status is non-zero
|
||||||
|
@@ -9,7 +9,7 @@ Postfix lookup table management
|
|||||||
.na
|
.na
|
||||||
.nf
|
.nf
|
||||||
.fi
|
.fi
|
||||||
\fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
\fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||||
[\fIfile_type\fR:]\fIfile_name\fR ...
|
[\fIfile_type\fR:]\fIfile_name\fR ...
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
.ad
|
.ad
|
||||||
@@ -44,12 +44,20 @@ special characters such as `#' or whitespace. The \fIkey\fR is mapped
|
|||||||
to lowercase to make mapping lookups case insensitive.
|
to lowercase to make mapping lookups case insensitive.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
.IP \fB-N\fR
|
||||||
|
Include the terminating null character that terminates lookup keys
|
||||||
|
and values. By default, Postfix does whatever is the default for
|
||||||
|
the host operating system.
|
||||||
.IP "\fB-c \fIconfig_dir\fR"
|
.IP "\fB-c \fIconfig_dir\fR"
|
||||||
Read the \fBmain.cf\fR configuration file in the named directory.
|
Read the \fBmain.cf\fR configuration file in the named directory.
|
||||||
.IP \fB-i\fR
|
.IP \fB-i\fR
|
||||||
Incremental mode. Read entries from standard input and do not
|
Incremental mode. Read entries from standard input and do not
|
||||||
truncate an existing database. By default, \fBpostmap\fR creates
|
truncate an existing database. By default, \fBpostmap\fR creates
|
||||||
a new database from the entries in \fBfile_name\fR.
|
a new database from the entries in \fBfile_name\fR.
|
||||||
|
.IP \fB-n\fR
|
||||||
|
Don't include the terminating null character that terminates lookup
|
||||||
|
keys and values. By default, Postfix does whatever is the default for
|
||||||
|
the host operating system.
|
||||||
.IP "\fB-q \fIkey\fR"
|
.IP "\fB-q \fIkey\fR"
|
||||||
Search the specified maps for \fIkey\fR and print the first value
|
Search the specified maps for \fIkey\fR and print the first value
|
||||||
found on the standard output stream. The exit status is non-zero
|
found on the standard output stream. The exit status is non-zero
|
||||||
|
@@ -5,8 +5,8 @@
|
|||||||
/* Postfix alias database maintenance
|
/* Postfix alias database maintenance
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* .fi
|
/* .fi
|
||||||
/* \fBpostalias\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
/* \fBpostalias\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR]
|
||||||
/* [\fIfile_type\fR:]\fIfile_name\fR ...
|
/* [\fB-q \fIkey\fR] [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* The \fBpostalias\fR command creates or queries one or more Postfix
|
/* The \fBpostalias\fR command creates or queries one or more Postfix
|
||||||
/* alias databases, or updates an existing one. The input and output
|
/* alias databases, or updates an existing one. The input and output
|
||||||
@@ -19,12 +19,20 @@
|
|||||||
/* programs.
|
/* programs.
|
||||||
/*
|
/*
|
||||||
/* Options:
|
/* Options:
|
||||||
|
/* .IP \fB-N\fR
|
||||||
|
/* Include the terminating null character that terminates lookup keys
|
||||||
|
/* and values. By default, Postfix does whatever is the default for
|
||||||
|
/* the host operating system.
|
||||||
/* .IP "\fB-c \fIconfig_dir\fR"
|
/* .IP "\fB-c \fIconfig_dir\fR"
|
||||||
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
||||||
/* .IP \fB-i\fR
|
/* .IP \fB-i\fR
|
||||||
/* Incremental mode. Read entries from standard input and do not
|
/* Incremental mode. Read entries from standard input and do not
|
||||||
/* truncate an existing database. By default, \fBpostalias\fR creates
|
/* truncate an existing database. By default, \fBpostalias\fR creates
|
||||||
/* a new database from the entries in \fBfile_name\fR.
|
/* a new database from the entries in \fBfile_name\fR.
|
||||||
|
/* .IP \fB-n\fR
|
||||||
|
/* Don't include the terminating null character that terminates lookup
|
||||||
|
/* keys and values. By default, Postfix does whatever is the default for
|
||||||
|
/* the host operating system.
|
||||||
/* .IP "\fB-q \fIkey\fR"
|
/* .IP "\fB-q \fIkey\fR"
|
||||||
/* Search the specified maps for \fIkey\fR and print the first value
|
/* Search the specified maps for \fIkey\fR and print the first value
|
||||||
/* found on the standard output stream. The exit status is non-zero
|
/* found on the standard output stream. The exit status is non-zero
|
||||||
@@ -297,7 +305,7 @@ static int postalias_query(const char *map_type, const char *map_name,
|
|||||||
|
|
||||||
static NORETURN usage(char *myname)
|
static NORETURN usage(char *myname)
|
||||||
{
|
{
|
||||||
msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
|
msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-q key] [map_type:]file...",
|
||||||
myname);
|
myname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,11 +354,15 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse JCL.
|
* Parse JCL.
|
||||||
*/
|
*/
|
||||||
while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
|
while ((ch = GETOPT(argc, argv, "Nc:inq:vw")) > 0) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
break;
|
break;
|
||||||
|
case 'N':
|
||||||
|
dict_flags |= DICT_FLAG_TRY1NULL;
|
||||||
|
dict_flags &= ~DICT_FLAG_TRY0NULL;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||||
msg_fatal("out of memory");
|
msg_fatal("out of memory");
|
||||||
@@ -358,6 +370,10 @@ int main(int argc, char **argv)
|
|||||||
case 'i':
|
case 'i':
|
||||||
open_flags &= ~O_TRUNC;
|
open_flags &= ~O_TRUNC;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
dict_flags |= DICT_FLAG_TRY0NULL;
|
||||||
|
dict_flags &= ~DICT_FLAG_TRY1NULL;
|
||||||
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
query = optarg;
|
query = optarg;
|
||||||
break;
|
break;
|
||||||
|
@@ -638,6 +638,9 @@ int main(int argc, char **argv)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
int junk;
|
int junk;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Be consistent with file permissions.
|
||||||
|
*/
|
||||||
umask(022);
|
umask(022);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -5,7 +5,7 @@
|
|||||||
/* Postfix lookup table management
|
/* Postfix lookup table management
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* .fi
|
/* .fi
|
||||||
/* \fBpostmap\fR [\fB-ivw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
/* \fBpostmap\fR [\fB-Ninvw\fR] [\fB-c \fIconfig_dir\fR] [\fB-q \fIkey\fR]
|
||||||
/* [\fIfile_type\fR:]\fIfile_name\fR ...
|
/* [\fIfile_type\fR:]\fIfile_name\fR ...
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* The \fBpostmap\fR command creates or queries one or more Postfix
|
/* The \fBpostmap\fR command creates or queries one or more Postfix
|
||||||
@@ -38,12 +38,20 @@
|
|||||||
/* to lowercase to make mapping lookups case insensitive.
|
/* to lowercase to make mapping lookups case insensitive.
|
||||||
/*
|
/*
|
||||||
/* Options:
|
/* Options:
|
||||||
|
/* .IP \fB-N\fR
|
||||||
|
/* Include the terminating null character that terminates lookup keys
|
||||||
|
/* and values. By default, Postfix does whatever is the default for
|
||||||
|
/* the host operating system.
|
||||||
/* .IP "\fB-c \fIconfig_dir\fR"
|
/* .IP "\fB-c \fIconfig_dir\fR"
|
||||||
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
/* Read the \fBmain.cf\fR configuration file in the named directory.
|
||||||
/* .IP \fB-i\fR
|
/* .IP \fB-i\fR
|
||||||
/* Incremental mode. Read entries from standard input and do not
|
/* Incremental mode. Read entries from standard input and do not
|
||||||
/* truncate an existing database. By default, \fBpostmap\fR creates
|
/* truncate an existing database. By default, \fBpostmap\fR creates
|
||||||
/* a new database from the entries in \fBfile_name\fR.
|
/* a new database from the entries in \fBfile_name\fR.
|
||||||
|
/* .IP \fB-n\fR
|
||||||
|
/* Don't include the terminating null character that terminates lookup
|
||||||
|
/* keys and values. By default, Postfix does whatever is the default for
|
||||||
|
/* the host operating system.
|
||||||
/* .IP "\fB-q \fIkey\fR"
|
/* .IP "\fB-q \fIkey\fR"
|
||||||
/* Search the specified maps for \fIkey\fR and print the first value
|
/* Search the specified maps for \fIkey\fR and print the first value
|
||||||
/* found on the standard output stream. The exit status is non-zero
|
/* found on the standard output stream. The exit status is non-zero
|
||||||
@@ -251,7 +259,7 @@ static int postmap_query(const char *map_type, const char *map_name,
|
|||||||
|
|
||||||
static NORETURN usage(char *myname)
|
static NORETURN usage(char *myname)
|
||||||
{
|
{
|
||||||
msg_fatal("usage: %s [-ivw] [-c config_dir] [-q key] [map_type:]file...",
|
msg_fatal("usage: %s [-Ninvw] [-c config_dir] [-q key] [map_type:]file...",
|
||||||
myname);
|
myname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,11 +308,15 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse JCL.
|
* Parse JCL.
|
||||||
*/
|
*/
|
||||||
while ((ch = GETOPT(argc, argv, "c:iq:vw")) > 0) {
|
while ((ch = GETOPT(argc, argv, "Nc:inq:vw")) > 0) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
default:
|
default:
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
break;
|
break;
|
||||||
|
case 'N':
|
||||||
|
dict_flags |= DICT_FLAG_TRY1NULL;
|
||||||
|
dict_flags &= ~DICT_FLAG_TRY0NULL;
|
||||||
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
|
||||||
msg_fatal("out of memory");
|
msg_fatal("out of memory");
|
||||||
@@ -312,6 +324,10 @@ int main(int argc, char **argv)
|
|||||||
case 'i':
|
case 'i':
|
||||||
open_flags &= ~O_TRUNC;
|
open_flags &= ~O_TRUNC;
|
||||||
break;
|
break;
|
||||||
|
case 'n':
|
||||||
|
dict_flags |= DICT_FLAG_TRY0NULL;
|
||||||
|
dict_flags &= ~DICT_FLAG_TRY1NULL;
|
||||||
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
query = optarg;
|
query = optarg;
|
||||||
break;
|
break;
|
||||||
|
@@ -137,7 +137,7 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Free the recipient list and decrease in-core recipient count
|
* Free the recipient list and decrease the in-core recipient count
|
||||||
* accordingly.
|
* accordingly.
|
||||||
*/
|
*/
|
||||||
qmgr_recipient_count -= entry->rcpt_list.len;
|
qmgr_recipient_count -= entry->rcpt_list.len;
|
||||||
@@ -160,10 +160,11 @@ void qmgr_entry_done(QMGR_ENTRY *entry, int which)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the in-core message reference count. When the in-core message
|
* Update the in-core message reference count. When the in-core message
|
||||||
* structure has no more references, dispose of the message. When the
|
* structure has no more references, dispose of the message.
|
||||||
* in-core recipient count falls below some threshold and this message
|
*
|
||||||
* has more recipients, read them from disk before concurrency starts to
|
* When the in-core recipient count falls below some threshold and this
|
||||||
* drop.
|
* message has more recipients, read more recipients before concurrency
|
||||||
|
* starts to drop.
|
||||||
*/
|
*/
|
||||||
message->refcount--;
|
message->refcount--;
|
||||||
if (message->refcount == 0)
|
if (message->refcount == 0)
|
||||||
|
@@ -222,6 +222,17 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
* may appear before or after the message content, so we keep reading
|
* may appear before or after the message content, so we keep reading
|
||||||
* from the queue file until we have enough recipients (rcpt_offset != 0)
|
* from the queue file until we have enough recipients (rcpt_offset != 0)
|
||||||
* and until we know where the message content starts (data_offset != 0).
|
* and until we know where the message content starts (data_offset != 0).
|
||||||
|
*
|
||||||
|
* When reading recipients from queue file, stop reading when we reach a
|
||||||
|
* per-message in-core recipient limit rather than a global in-core
|
||||||
|
* recipient limit. Use the global recipient limit only in order to stop
|
||||||
|
* opening queue files. The purpose is to achieve equal delay for
|
||||||
|
* messages with recipient counts up to var_qmgr_rcpt_limit recipients.
|
||||||
|
*
|
||||||
|
* If we would read recipients up to a global recipient limit, the average
|
||||||
|
* number of in-core recipients per message would asymptotically approach
|
||||||
|
* (global recipient limit)/(active queue size limit), which gives equal
|
||||||
|
* delay per recipient rather than equal delay per message.
|
||||||
*/
|
*/
|
||||||
do {
|
do {
|
||||||
if ((curr_offset = vstream_ftell(message->fp)) < 0)
|
if ((curr_offset = vstream_ftell(message->fp)) < 0)
|
||||||
@@ -241,10 +252,9 @@ static int qmgr_message_read(QMGR_MESSAGE *message)
|
|||||||
message->data_size, "queue %s", message->queue_name);
|
message->data_size, "queue %s", message->queue_name);
|
||||||
}
|
}
|
||||||
} else if (rec_type == REC_TYPE_RCPT) {
|
} else if (rec_type == REC_TYPE_RCPT) {
|
||||||
#define TOTAL_RECIPIENT_COUNT (qmgr_recipient_count + message->rcpt_list.len)
|
if (message->rcpt_list.len < var_qmgr_rcpt_limit) {
|
||||||
if (TOTAL_RECIPIENT_COUNT < var_qmgr_rcpt_limit) {
|
|
||||||
qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
|
qmgr_rcpt_list_add(&message->rcpt_list, curr_offset, start);
|
||||||
if (TOTAL_RECIPIENT_COUNT >= var_qmgr_rcpt_limit) {
|
if (message->rcpt_list.len >= var_qmgr_rcpt_limit) {
|
||||||
if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
|
if ((message->rcpt_offset = vstream_ftell(message->fp)) < 0)
|
||||||
msg_fatal("vstream_ftell %s: %m",
|
msg_fatal("vstream_ftell %s: %m",
|
||||||
VSTREAM_PATH(message->fp));
|
VSTREAM_PATH(message->fp));
|
||||||
|
@@ -224,20 +224,39 @@ static const char *dict_ldap_lookup(DICT *dict, const char *name)
|
|||||||
escaped_name = vstring_alloc(20);
|
escaped_name = vstring_alloc(20);
|
||||||
filter_buf = vstring_alloc(30);
|
filter_buf = vstring_alloc(30);
|
||||||
|
|
||||||
/* Any wildcards and escapes in the supplied address should be escaped. */
|
/*
|
||||||
if (strchr(name, '*') || strchr(name, '\\')) {
|
* If any characters in the supplied address should be escaped per RFC
|
||||||
|
* 2254, do so.
|
||||||
|
*/
|
||||||
|
|
||||||
|
end = (char *) name + strlen((char *) name);
|
||||||
|
sub = (char *) strpbrk((char *) name, "*()\\\0");
|
||||||
|
if (sub && sub != end) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: found wildcard in %s", myname, name);
|
msg_info("%s: found character(s) in %s that must be escaped", myname, name);
|
||||||
for (sub = (char *) name; *sub != '\0'; sub++) {
|
for (sub = (char *) name; sub != end; sub++) {
|
||||||
if (*sub == '*' || *sub == '\\') {
|
switch (*sub) {
|
||||||
vstring_strncat(escaped_name, "\\", 1);
|
case '*':
|
||||||
vstring_strncat(escaped_name, sub, 1);
|
vstring_strcat(escaped_name, "\\2a");
|
||||||
} else {
|
break;
|
||||||
|
case '(':
|
||||||
|
vstring_strcat(escaped_name, "\\28");
|
||||||
|
break;
|
||||||
|
case ')':
|
||||||
|
vstring_strcat(escaped_name, "\\29");
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
vstring_strcat(escaped_name, "\\5c");
|
||||||
|
break;
|
||||||
|
case '\0':
|
||||||
|
vstring_strcat(escaped_name, "\\00");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
vstring_strncat(escaped_name, sub, 1);
|
vstring_strncat(escaped_name, sub, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: with wildcards escaped, it's %s", myname, vstring_str(escaped_name));
|
msg_info("%s: after escaping, it's %s", myname, vstring_str(escaped_name));
|
||||||
} else
|
} else
|
||||||
vstring_strcpy(escaped_name, (char *) name);
|
vstring_strcpy(escaped_name, (char *) name);
|
||||||
|
|
||||||
|
@@ -12,11 +12,19 @@
|
|||||||
/* int dummy;
|
/* int dummy;
|
||||||
/* int unused_dict_flags;
|
/* int unused_dict_flags;
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* dict_mysql_open() opens the mysql databases with name dbname on
|
/* dict_mysql_open() creates a dictionary of type 'mysql'. This
|
||||||
/* each host in hostlist and registers under the given name with the
|
/* dictionary is an interface for the postfix key->value mappings
|
||||||
/* dictionary manager. The result is a pointer to the installed dictionary,
|
/* to mysql. The result is a pointer to the installed dictionary,
|
||||||
/* or a null pointer in case of problems.
|
/* or a null pointer in case of problems.
|
||||||
/*
|
/*
|
||||||
|
/* The mysql dictionary can manage multiple connections to different
|
||||||
|
/* sql servers on different hosts. It assumes that the underlying data
|
||||||
|
/* on each host is identical (mirrored) and maintains one connection
|
||||||
|
/* at any given time. If any connection fails, any other available
|
||||||
|
/* ones will be opened and used. The intent of this feature is to eliminate
|
||||||
|
/* a single point of failure for mail systems that would otherwise rely
|
||||||
|
/* on a single mysql server.
|
||||||
|
/*
|
||||||
/* Arguments:
|
/* Arguments:
|
||||||
/* .IP name
|
/* .IP name
|
||||||
/* The path of the MySQL configuration file. The file encodes a number of
|
/* The path of the MySQL configuration file. The file encodes a number of
|
||||||
@@ -70,8 +78,24 @@
|
|||||||
#include "argv.h"
|
#include "argv.h"
|
||||||
#include "vstring.h"
|
#include "vstring.h"
|
||||||
|
|
||||||
|
/* external declarations */
|
||||||
extern int dict_errno;
|
extern int dict_errno;
|
||||||
|
|
||||||
|
/* need some structs to help organize things */
|
||||||
|
typedef struct {
|
||||||
|
MYSQL db;
|
||||||
|
char *hostname;
|
||||||
|
int stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
||||||
|
time_t ts; /* used for attempting reconnection
|
||||||
|
* every so often if a host is down */
|
||||||
|
} HOST;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int len_hosts; /* number of hosts */
|
||||||
|
HOST *db_hosts; /* the hosts on which the databases
|
||||||
|
* reside */
|
||||||
|
} PLMYSQL;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *username;
|
char *username;
|
||||||
char *password;
|
char *password;
|
||||||
@@ -90,114 +114,38 @@ typedef struct {
|
|||||||
MYSQL_NAME *name;
|
MYSQL_NAME *name;
|
||||||
} DICT_MYSQL;
|
} DICT_MYSQL;
|
||||||
|
|
||||||
/* mysqlname_parse - parse mysql configuration file */
|
/* internal function declarations */
|
||||||
|
static PLMYSQL *plmysql_init(char *hostnames[], int);
|
||||||
|
static MYSQL_RES *plmysql_query(PLMYSQL *, const char *, char *, char *, char *);
|
||||||
|
static void plmysql_dealloc(PLMYSQL *);
|
||||||
|
static void plmysql_down_host(HOST *);
|
||||||
|
static void plmysql_connect_single(HOST *, char *, char *, char *);
|
||||||
|
static int plmysql_ready_reconn(HOST);
|
||||||
|
static void dict_mysql_update(DICT *, const char *, const char *);
|
||||||
|
static const char *dict_mysql_lookup(DICT *, const char *);
|
||||||
|
DICT *dict_mysql_open(const char *, int, int);
|
||||||
|
static void dict_mysql_close(DICT *);
|
||||||
|
static MYSQL_NAME *mysqlname_parse(const char *);
|
||||||
|
static HOST host_init(char *);
|
||||||
|
|
||||||
static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
char *nameval;
|
|
||||||
char *hosts;
|
|
||||||
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
|
||||||
ARGV *hosts_argv;
|
|
||||||
|
|
||||||
dict_load_file("mysql_options", mysqlcf_path);
|
|
||||||
/* mysql username lookup */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "user")) == NULL)
|
|
||||||
name->username = mystrdup("");
|
|
||||||
else
|
|
||||||
name->username = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("dict_mysql_parse: set username to '%s'", name->username);
|
|
||||||
/* password lookup */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "password")) == NULL)
|
|
||||||
name->password = mystrdup("");
|
|
||||||
else
|
|
||||||
name->password = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("dict_mysql_parse: set password to '%s'", name->password);
|
|
||||||
|
|
||||||
/* database name lookup */
|
/**********************************************************************
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "dbname")) == NULL)
|
* public interface dict_mysql_lookup
|
||||||
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
* find database entry return 0 if no alias found, set dict_errno
|
||||||
else
|
* on errors to DICT_ERRBO_RETRY and set dict_errno to 0 on success
|
||||||
name->dbname = mystrdup(nameval);
|
*********************************************************************/
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("mysql_name_parse: set database name to '%s'", name->dbname);
|
|
||||||
|
|
||||||
/* table lookup */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "table")) == NULL)
|
|
||||||
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
|
||||||
else
|
|
||||||
name->table = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("mysql_name_parse: set table name to '%s'", name->table);
|
|
||||||
|
|
||||||
/* select field lookup */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "select_field")) == NULL)
|
|
||||||
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
|
||||||
else
|
|
||||||
name->select_field = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("mysql_name_parse: set select_field to '%s'", name->select_field);
|
|
||||||
|
|
||||||
/* where field lookup */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "where_field")) == NULL)
|
|
||||||
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
|
||||||
else
|
|
||||||
name->where_field = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("mysql_name_parse: set where_field to '%s'", name->where_field);
|
|
||||||
|
|
||||||
/* additional conditions */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "additional_conditions")) == NULL)
|
|
||||||
name->additional_conditions = mystrdup("");
|
|
||||||
else
|
|
||||||
name->additional_conditions = mystrdup(nameval);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("mysql_name_parse: set additional_conditions to '%s'", name->additional_conditions);
|
|
||||||
|
|
||||||
/* mysql server hosts */
|
|
||||||
if ((nameval = (char *) dict_lookup("mysql_options", "hosts")) == NULL)
|
|
||||||
hosts = mystrdup("");
|
|
||||||
else
|
|
||||||
hosts = mystrdup(nameval);
|
|
||||||
/* coo argv interface */
|
|
||||||
hosts_argv = argv_split(hosts, " ");
|
|
||||||
argv_terminate(hosts_argv);
|
|
||||||
|
|
||||||
if (hosts_argv->argc == 0) { /* no hosts specified,
|
|
||||||
* default to 'localhost' */
|
|
||||||
msg_info("mysql_name_parse: no hostnames specified, defaulting to 'localhost'");
|
|
||||||
name->len_hosts = 1;
|
|
||||||
name->hostnames = (char **) mymalloc(sizeof(char *));
|
|
||||||
name->hostnames[0] = mystrdup("localhost");
|
|
||||||
} else {
|
|
||||||
name->len_hosts = hosts_argv->argc;
|
|
||||||
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
|
||||||
i = 0;
|
|
||||||
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
|
||||||
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
|
||||||
if (msg_verbose)
|
|
||||||
msg_info("adding host '%s' to list of mysql server hosts", name->hostnames[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
myfree(hosts);
|
|
||||||
argv_free(hosts_argv);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dict_mysql_lookup - find database entry return 0 if no alias found */
|
|
||||||
static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
||||||
{
|
{
|
||||||
MYSQL_RES *query_res;
|
MYSQL_RES *query_res;
|
||||||
MYSQL_ROW row;
|
MYSQL_ROW row;
|
||||||
int i,
|
|
||||||
numrows;
|
|
||||||
static VSTRING *result;
|
|
||||||
static VSTRING *query = 0;
|
|
||||||
char *name_escaped = 0;
|
|
||||||
DICT_MYSQL *dict_mysql;
|
DICT_MYSQL *dict_mysql;
|
||||||
PLMYSQL *pldb;
|
PLMYSQL *pldb;
|
||||||
|
static VSTRING *result;
|
||||||
|
static VSTRING *query = 0;
|
||||||
|
int i,
|
||||||
|
numrows;
|
||||||
|
char *name_escaped = 0;
|
||||||
|
|
||||||
dict_mysql = (DICT_MYSQL *) dict;
|
dict_mysql = (DICT_MYSQL *) dict;
|
||||||
pldb = dict_mysql->pldb;
|
pldb = dict_mysql->pldb;
|
||||||
@@ -216,8 +164,12 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
|||||||
msg_info("dict_mysql_lookup using sql query: %s", vstring_str(query));
|
msg_info("dict_mysql_lookup using sql query: %s", vstring_str(query));
|
||||||
/* free mem associated with preparing the query */
|
/* free mem associated with preparing the query */
|
||||||
myfree(name_escaped);
|
myfree(name_escaped);
|
||||||
/* do the query */
|
/* do the query - set dict_errno & cleanup if there's an error */
|
||||||
if ((query_res = plmysql_query(pldb, vstring_str(query))) == NULL) {
|
if ((query_res = plmysql_query(pldb,
|
||||||
|
vstring_str(query),
|
||||||
|
dict_mysql->name->dbname,
|
||||||
|
dict_mysql->name->username,
|
||||||
|
dict_mysql->name->password)) == 0) {
|
||||||
dict_errno = DICT_ERR_RETRY;
|
dict_errno = DICT_ERR_RETRY;
|
||||||
vstring_free(query);
|
vstring_free(query);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -247,7 +199,303 @@ static const char *dict_mysql_lookup(DICT *dict, const char *name)
|
|||||||
return vstring_str(result);
|
return vstring_str(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_mysql_close - unregister, disassociate from database */
|
/*
|
||||||
|
* plmysql_query - process a MySQL query. Return MYSQL_RES* on success.
|
||||||
|
* On failure, log failure and try other db instances.
|
||||||
|
* on failure of all db instances, return 0;
|
||||||
|
* close unnecessary active connections
|
||||||
|
*/
|
||||||
|
|
||||||
|
static MYSQL_RES *plmysql_query(PLMYSQL *PLDB,
|
||||||
|
const char *query,
|
||||||
|
char *dbname,
|
||||||
|
char *username,
|
||||||
|
char *password)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
HOST *host;
|
||||||
|
MYSQL_RES *res = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < PLDB->len_hosts; i++) {
|
||||||
|
/* can't deal with typing or reading PLDB->db_hosts[i] over & over */
|
||||||
|
host = &(PLDB->db_hosts[i]);
|
||||||
|
if (msg_verbose > 1)
|
||||||
|
msg_info("dict_mysql: trying host %s stat %d, last res %p", host->hostname, host->stat, res);
|
||||||
|
|
||||||
|
/* answer already found */
|
||||||
|
if (res != 0 && host->stat == STATACTIVE) {
|
||||||
|
msg_info("dict_mysql: closing unnessary connection to %s", host->hostname);
|
||||||
|
mysql_close(&(host->db)); /* also frees memory, have to
|
||||||
|
* reallocate it */
|
||||||
|
host->db = *((MYSQL *) mymalloc(sizeof(MYSQL)));
|
||||||
|
plmysql_down_host(host);
|
||||||
|
}
|
||||||
|
/* try to connect for the first time if we don't have a result yet */
|
||||||
|
if (res == 0 && host->stat == STATUNTRIED) {
|
||||||
|
msg_info("dict_mysql: attempting to connect to host %s", host->hostname);
|
||||||
|
plmysql_connect_single(host, dbname, username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try to reconnect if we don't have an answer and the host had a
|
||||||
|
* prob in the past and it's time for it to reconnect
|
||||||
|
*/
|
||||||
|
if (res == 0 && host->stat == STATFAIL && (plmysql_ready_reconn(*host))) {
|
||||||
|
msg_warn("dict_mysql: attempting to reconnect to host %s", host->hostname);
|
||||||
|
plmysql_connect_single(host, dbname, username, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if we don't have a result and the current host is marked active,
|
||||||
|
* try the query. If the query fails, mark the host STATFAIL
|
||||||
|
*/
|
||||||
|
if (res == 0 && host->stat == STATACTIVE) {
|
||||||
|
if (!(mysql_query(&(host->db), query))) {
|
||||||
|
if ((res = mysql_store_result(&(host->db))) == 0) {
|
||||||
|
msg_warn("%s", mysql_error(&(host->db)));
|
||||||
|
plmysql_down_host(host);
|
||||||
|
} else {
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("dict_mysql: successful query from host %s", host->hostname);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg_warn("%s", mysql_error(&(host->db)));
|
||||||
|
plmysql_down_host(host);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plmysql_connect_single -
|
||||||
|
* used to reconnect to a single database when one is down or none is
|
||||||
|
* connected yet. Log all errors and set the stat field of host accordingly
|
||||||
|
*/
|
||||||
|
static void plmysql_connect_single(HOST *host, char *dbname, char *username, char *password)
|
||||||
|
{
|
||||||
|
if (mysql_connect(&(host->db), host->hostname, username, password)) {
|
||||||
|
if (mysql_select_db(&(host->db), dbname) == 0) {
|
||||||
|
msg_info("dict_mysql: successful connection to host %s", host->hostname);
|
||||||
|
host->stat = STATACTIVE;
|
||||||
|
} else {
|
||||||
|
plmysql_down_host(host);
|
||||||
|
msg_warn("%s", mysql_error(&(host->db)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
plmysql_down_host(host);
|
||||||
|
msg_warn("%s", mysql_error(&(host->db)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plmysql_down_host - mark a HOST down update ts if marked down
|
||||||
|
* for the first time so that we'll know when to retry the connection
|
||||||
|
*/
|
||||||
|
static void plmysql_down_host(HOST *host)
|
||||||
|
{
|
||||||
|
if (host->stat != STATFAIL) {
|
||||||
|
host->ts = time(&(host->ts));
|
||||||
|
host->stat = STATFAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plmysql_ready_reconn -
|
||||||
|
* given a downed HOST, return whether or not it should retry connection
|
||||||
|
*/
|
||||||
|
static int plmysql_ready_reconn(HOST host)
|
||||||
|
{
|
||||||
|
time_t t;
|
||||||
|
long now;
|
||||||
|
|
||||||
|
now = (long) time(&t);
|
||||||
|
if (msg_verbose > 1) {
|
||||||
|
msg_info("dict_mysql: plmysql_ready_reconn(): now is %d", now);
|
||||||
|
msg_info("dict_mysql: plmysql_ready_reconn(): ts is %d", (long) host.ts);
|
||||||
|
msg_info("dict_mysql: plmysql_ready_reconn(): RETRY_CONN_INTV is %d", RETRY_CONN_INTV);
|
||||||
|
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV) {
|
||||||
|
msg_info("dict_mysql: plymsql_ready_reconn(): returning TRUE");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
msg_info("dict_mysql: plymsql_ready_reconn(): returning FALSE");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* public interface dict_mysql_open
|
||||||
|
* create association with database with appropriate values
|
||||||
|
* parse the map's config file
|
||||||
|
* allocate memory
|
||||||
|
**********************************************************************/
|
||||||
|
DICT *dict_mysql_open(const char *name, int unused_flags, int unused_dict_flags)
|
||||||
|
{
|
||||||
|
DICT_MYSQL *dict_mysql;
|
||||||
|
int connections;
|
||||||
|
|
||||||
|
dict_mysql = (DICT_MYSQL *) mymalloc(sizeof(DICT_MYSQL));
|
||||||
|
dict_mysql->dict.lookup = dict_mysql_lookup;
|
||||||
|
dict_mysql->dict.update = dict_mysql_update;
|
||||||
|
dict_mysql->dict.close = dict_mysql_close;
|
||||||
|
dict_mysql->dict.fd = -1; /* there's no file descriptor
|
||||||
|
* for locking */
|
||||||
|
dict_mysql->name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||||
|
dict_mysql->name = mysqlname_parse(name);
|
||||||
|
dict_mysql->pldb = plmysql_init(dict_mysql->name->hostnames,
|
||||||
|
dict_mysql->name->len_hosts);
|
||||||
|
if (dict_mysql->pldb == NULL)
|
||||||
|
msg_fatal("couldn't intialize pldb!\n");
|
||||||
|
dict_register(name, (DICT *) dict_mysql);
|
||||||
|
return &dict_mysql->dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mysqlname_parse - parse mysql configuration file */
|
||||||
|
static MYSQL_NAME *mysqlname_parse(const char *mysqlcf_path)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char *nameval;
|
||||||
|
char *hosts;
|
||||||
|
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
||||||
|
ARGV *hosts_argv;
|
||||||
|
|
||||||
|
dict_load_file("mysql_options", mysqlcf_path);
|
||||||
|
/* mysql username lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "user")) == NULL)
|
||||||
|
name->username = mystrdup("");
|
||||||
|
else
|
||||||
|
name->username = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set username to '%s'", name->username);
|
||||||
|
/* password lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "password")) == NULL)
|
||||||
|
name->password = mystrdup("");
|
||||||
|
else
|
||||||
|
name->password = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set password to '%s'", name->password);
|
||||||
|
|
||||||
|
/* database name lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "dbname")) == NULL)
|
||||||
|
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
|
||||||
|
else
|
||||||
|
name->dbname = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set database name to '%s'", name->dbname);
|
||||||
|
|
||||||
|
/* table lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "table")) == NULL)
|
||||||
|
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
|
||||||
|
else
|
||||||
|
name->table = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set table name to '%s'", name->table);
|
||||||
|
|
||||||
|
/* select field lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "select_field")) == NULL)
|
||||||
|
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
|
||||||
|
else
|
||||||
|
name->select_field = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set select_field to '%s'", name->select_field);
|
||||||
|
|
||||||
|
/* where field lookup */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "where_field")) == NULL)
|
||||||
|
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
|
||||||
|
else
|
||||||
|
name->where_field = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set where_field to '%s'", name->where_field);
|
||||||
|
|
||||||
|
/* additional conditions */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "additional_conditions")) == NULL)
|
||||||
|
name->additional_conditions = mystrdup("");
|
||||||
|
else
|
||||||
|
name->additional_conditions = mystrdup(nameval);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): set additional_conditions to '%s'", name->additional_conditions);
|
||||||
|
|
||||||
|
/* mysql server hosts */
|
||||||
|
if ((nameval = (char *) dict_lookup("mysql_options", "hosts")) == NULL)
|
||||||
|
hosts = mystrdup("");
|
||||||
|
else
|
||||||
|
hosts = mystrdup(nameval);
|
||||||
|
/* coo argv interface */
|
||||||
|
hosts_argv = argv_split(hosts, " ");
|
||||||
|
argv_terminate(hosts_argv);
|
||||||
|
|
||||||
|
if (hosts_argv->argc == 0) { /* no hosts specified,
|
||||||
|
* default to 'localhost' */
|
||||||
|
msg_info("mysqlname_parse(): no hostnames specified, defaulting to 'localhost'");
|
||||||
|
name->len_hosts = 1;
|
||||||
|
name->hostnames = (char **) mymalloc(sizeof(char *));
|
||||||
|
name->hostnames[0] = mystrdup("localhost");
|
||||||
|
} else {
|
||||||
|
name->len_hosts = hosts_argv->argc;
|
||||||
|
name->hostnames = (char **) mymalloc((sizeof(char *)) * name->len_hosts);
|
||||||
|
i = 0;
|
||||||
|
for (i = 0; hosts_argv->argv[i] != NULL; i++) {
|
||||||
|
name->hostnames[i] = mystrdup(hosts_argv->argv[i]);
|
||||||
|
if (msg_verbose)
|
||||||
|
msg_info("mysqlname_parse(): adding host '%s' to list of mysql server hosts",
|
||||||
|
name->hostnames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myfree(hosts);
|
||||||
|
argv_free(hosts_argv);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* plmysql_init - initalize a MYSQL database.
|
||||||
|
* Return NULL on failure, or a PLMYSQL * on success.
|
||||||
|
*/
|
||||||
|
static PLMYSQL *plmysql_init(char *hostnames[],
|
||||||
|
int len_hosts)
|
||||||
|
{
|
||||||
|
PLMYSQL *PLDB;
|
||||||
|
MYSQL *dbs;
|
||||||
|
int i;
|
||||||
|
HOST host;
|
||||||
|
|
||||||
|
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == NULL) {
|
||||||
|
msg_fatal("mymalloc of pldb failed");
|
||||||
|
}
|
||||||
|
PLDB->len_hosts = len_hosts;
|
||||||
|
if ((PLDB->db_hosts = (HOST *) mymalloc(sizeof(HOST) * len_hosts)) == NULL)
|
||||||
|
return NULL;
|
||||||
|
for (i = 0; i < len_hosts; i++) {
|
||||||
|
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
||||||
|
}
|
||||||
|
return PLDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* host_init - initialize HOST structure */
|
||||||
|
static HOST host_init(char *hostname)
|
||||||
|
{
|
||||||
|
int stat;
|
||||||
|
MYSQL db;
|
||||||
|
time_t ts;
|
||||||
|
HOST host;
|
||||||
|
|
||||||
|
host.stat = STATUNTRIED;
|
||||||
|
host.hostname = hostname;
|
||||||
|
host.db = db;
|
||||||
|
host.ts = ts;
|
||||||
|
return host;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************************************************************
|
||||||
|
* public interface dict_mysql_close
|
||||||
|
* unregister, disassociate from database, freeing appropriate memory
|
||||||
|
**********************************************************************/
|
||||||
static void dict_mysql_close(DICT *dict)
|
static void dict_mysql_close(DICT *dict)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -267,87 +515,8 @@ static void dict_mysql_close(DICT *dict)
|
|||||||
myfree((char *) dict_mysql->name);
|
myfree((char *) dict_mysql->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* dict_mysql_update - add or update table entry */
|
|
||||||
static void dict_mysql_update(DICT *dict, const char *unused_name, const char *unused_value)
|
|
||||||
{
|
|
||||||
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
|
||||||
|
|
||||||
msg_fatal("dict_mysql_update: attempt to update mysql database");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* dict_mysql_open - create association with database */
|
|
||||||
DICT *dict_mysql_open(const char *name, int unused_flags, int unused_dict_flags)
|
|
||||||
{
|
|
||||||
DICT_MYSQL *dict_mysql;
|
|
||||||
int connections;
|
|
||||||
|
|
||||||
dict_mysql = (DICT_MYSQL *) mymalloc(sizeof(DICT_MYSQL));
|
|
||||||
dict_mysql->dict.lookup = dict_mysql_lookup;
|
|
||||||
dict_mysql->dict.update = dict_mysql_update;
|
|
||||||
dict_mysql->dict.close = dict_mysql_close;
|
|
||||||
dict_mysql->dict.fd = -1; /* there's no file descriptor
|
|
||||||
* for locking */
|
|
||||||
dict_mysql->name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
|
|
||||||
dict_mysql->name = mysqlname_parse(name);
|
|
||||||
dict_mysql->pldb = plmysql_init(dict_mysql->name->dbname,
|
|
||||||
dict_mysql->name->hostnames,
|
|
||||||
dict_mysql->name->len_hosts);
|
|
||||||
if (dict_mysql->pldb == NULL)
|
|
||||||
msg_fatal("couldn't intialize pldb!\n");
|
|
||||||
connections = plmysql_connect(dict_mysql->pldb, dict_mysql->name->username,
|
|
||||||
dict_mysql->name->password);
|
|
||||||
if (connections == 0)
|
|
||||||
/* the mysql lookup mechanism will try to reconnect anyway ... */
|
|
||||||
msg_warn("couldn't connect pldb to any database instances");
|
|
||||||
else
|
|
||||||
msg_info("pldb connected to %d database instances", connections);
|
|
||||||
dict_register(name, (DICT *) dict_mysql);
|
|
||||||
return &dict_mysql->dict;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* host_init - initialize HOST structure */
|
|
||||||
static HOST host_init(char *hostname)
|
|
||||||
{
|
|
||||||
int stat;
|
|
||||||
MYSQL db;
|
|
||||||
time_t ts;
|
|
||||||
HOST host;
|
|
||||||
|
|
||||||
host.stat = STATUNTRIED;
|
|
||||||
host.hostname = hostname;
|
|
||||||
host.db = db;
|
|
||||||
host.ts = ts;
|
|
||||||
return host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* plmysql_init - initalize a MYSQL database.
|
|
||||||
* Return NULL on failure, or a PLMYSQL * on success.
|
|
||||||
*/
|
|
||||||
PLMYSQL *plmysql_init(char *dbname,
|
|
||||||
char *hostnames[],
|
|
||||||
int len_hosts)
|
|
||||||
{
|
|
||||||
PLMYSQL *PLDB;
|
|
||||||
MYSQL *dbs;
|
|
||||||
int i;
|
|
||||||
HOST host;
|
|
||||||
|
|
||||||
if ((PLDB = (PLMYSQL *) mymalloc(sizeof(PLMYSQL))) == NULL) {
|
|
||||||
msg_fatal("mymalloc of pldb failed");
|
|
||||||
}
|
|
||||||
PLDB->dbname = dbname;
|
|
||||||
PLDB->len_hosts = len_hosts;
|
|
||||||
if ((PLDB->db_hosts = (HOST *) mymalloc(sizeof(HOST) * len_hosts)) == NULL)
|
|
||||||
return NULL;
|
|
||||||
for (i = 0; i < len_hosts; i++) {
|
|
||||||
PLDB->db_hosts[i] = host_init(hostnames[i]);
|
|
||||||
}
|
|
||||||
return PLDB;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* plmysql_dealloc - free memory associated with PLMYSQL close databases */
|
/* plmysql_dealloc - free memory associated with PLMYSQL close databases */
|
||||||
void plmysql_dealloc(PLMYSQL *PLDB)
|
static void plmysql_dealloc(PLMYSQL *PLDB)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -359,96 +528,16 @@ void plmysql_dealloc(PLMYSQL *PLDB)
|
|||||||
myfree((char *) (PLDB));
|
myfree((char *) (PLDB));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* plmysql_down_host - down a HOST * */
|
|
||||||
inline void plmysql_down_host(HOST *host)
|
/**********************************************************************
|
||||||
|
* public interface dict_mysql_update - add or update table entry
|
||||||
|
*
|
||||||
|
*********************************************************************/
|
||||||
|
static void dict_mysql_update(DICT *dict, const char *unused_name, const char *unused_value)
|
||||||
{
|
{
|
||||||
if (host->stat != STATFAIL)
|
DICT_MYSQL *dict_mysql = (DICT_MYSQL *) dict;
|
||||||
host->ts = time(&(host->ts));
|
|
||||||
host->stat = STATFAIL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* plmysql_connect_single -
|
msg_fatal("dict_mysql_update: attempt to update mysql database");
|
||||||
* used to reconnect to a single database when one is down and as a helper for
|
|
||||||
* plmysql_connect
|
|
||||||
*/
|
|
||||||
int plmysql_connect_single(PLMYSQL *PLDB, int host)
|
|
||||||
{
|
|
||||||
if ((mysql_connect(&(PLDB->db_hosts[host].db), PLDB->db_hosts[host].hostname,
|
|
||||||
PLDB->username, PLDB->password))) {
|
|
||||||
if (mysql_select_db(&(PLDB->db_hosts[host].db), PLDB->dbname) == 0) {
|
|
||||||
PLDB->db_hosts[host].stat = STATACTIVE;
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
plmysql_down_host(&(PLDB->db_hosts[host]));
|
|
||||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[host].db));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
plmysql_down_host(&(PLDB->db_hosts[host]));
|
|
||||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[host].db));
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* plmysql_connect -
|
|
||||||
* given a PLMYSQL struct PLDB *, connect it and select db.
|
|
||||||
* return the number of databases successfully connected (0 for failure)
|
|
||||||
*/
|
|
||||||
int plmysql_connect(PLMYSQL *PLDB, char *username, char *password)
|
|
||||||
{
|
|
||||||
int i,
|
|
||||||
res;
|
|
||||||
|
|
||||||
res = 0;
|
|
||||||
|
|
||||||
PLDB->username = username;
|
|
||||||
PLDB->password = password;
|
|
||||||
|
|
||||||
for (i = 0; i < PLDB->len_hosts; i++) {
|
|
||||||
res = res + plmysql_connect_single(PLDB, i);
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* plmysql_ready_reconn -
|
|
||||||
given a downed HOST, return whether or not it should retry connection
|
|
||||||
*/
|
|
||||||
int plmysql_ready_reconn(HOST host)
|
|
||||||
{
|
|
||||||
time_t t;
|
|
||||||
long now;
|
|
||||||
|
|
||||||
now = (long) time(&t);
|
|
||||||
if ((now - ((long) host.ts)) >= RETRY_CONN_INTV)
|
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* plmysql_query - process a MySQL query. Return 0 on success.
|
|
||||||
* On failure, log failure and try other db instances.
|
|
||||||
*/
|
|
||||||
|
|
||||||
MYSQL_RES *plmysql_query(PLMYSQL *PLDB, const char *query)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
MYSQL_RES *res;
|
|
||||||
|
|
||||||
for (i = 0; i < PLDB->len_hosts; i++) {
|
|
||||||
if ((PLDB->db_hosts[i].stat != STATACTIVE) &&
|
|
||||||
(plmysql_ready_reconn(PLDB->db_hosts[i]))) {
|
|
||||||
msg_warn("attempting to reconnect to host");
|
|
||||||
plmysql_connect_single(PLDB, i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if ((!(mysql_query(&(PLDB->db_hosts[i].db), query))) && \
|
|
||||||
(res = mysql_store_result(&(PLDB->db_hosts[i].db)))) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
msg_warn("%s", mysql_error(&PLDB->db_hosts[i].db));
|
|
||||||
plmysql_down_host(&(PLDB->db_hosts[i]));
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -6,41 +6,9 @@
|
|||||||
#define STATACTIVE 0
|
#define STATACTIVE 0
|
||||||
#define STATFAIL 1
|
#define STATFAIL 1
|
||||||
#define STATUNTRIED 2
|
#define STATUNTRIED 2
|
||||||
#define RETRY_CONN_INTV 300 /* 5 minutes */
|
#define RETRY_CONN_INTV 60 /* 1 minute */
|
||||||
|
|
||||||
extern DICT *dict_mysql_open(const char *name, int unused_flags, int dict_flags);
|
extern DICT *dict_mysql_open(const char *name, int unused_flags, int dict_flags);
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *hostname;
|
|
||||||
int stat; /* STATUNTRIED | STATFAIL | STATCUR */
|
|
||||||
time_t ts; /* used for attempting reconnection
|
|
||||||
* every so often if a host is down */
|
|
||||||
MYSQL db;
|
|
||||||
} HOST;
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char *username; /* login for database */
|
|
||||||
char *password; /* password for database */
|
|
||||||
char *dbname; /* the name of the database on all
|
|
||||||
* the servers */
|
|
||||||
HOST *db_hosts; /* the hosts on which the databases
|
|
||||||
* reside */
|
|
||||||
int len_hosts; /* number of hosts */
|
|
||||||
} PLMYSQL;
|
|
||||||
|
|
||||||
extern PLMYSQL *plmysql_init(char *dbname, char *hostnames[], int len_hosts);
|
|
||||||
|
|
||||||
extern int plmysql_connect(PLMYSQL *PLDB, char *username, char *password);
|
|
||||||
|
|
||||||
MYSQL_RES *plmysql_query(PLMYSQL *PLDB, const char *query);
|
|
||||||
|
|
||||||
void plmysql_dealloc(PLMYSQL *PLDB);
|
|
||||||
|
|
||||||
inline void plmysql_down_host(HOST *host);
|
|
||||||
|
|
||||||
int plmysql_connect_single(PLMYSQL *PLDB, int host);
|
|
||||||
|
|
||||||
int plmysql_ready_reconn(HOST host);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Reference in New Issue
Block a user