Debug version display reports library info.
Bumps lookup API magic constant, adds new field to module API.
When invoking { exim -d -bV } we can display more version information.
Show versions for many external libraries, including both compile-time
and run-time information if we can.
Optional for modules, may be NULL. Implemented for MySQL, SQLite &
Whoson lookups. For all lookups, if dynamically loaded, report the
Exim version number from the build. (Packagers will bundle stuff, but
dynamic modules are no longer just available for packagers, so we need
to deal with less managed environments and people forgetting to install
new modules).
Suggest in EDITME that users of modules not using package management
consider embedding a version number in the path to the modules.
Should consider removing the TLS (OpenSSL/GnuTLS) reporting from the
default -bV display and moving it into the debug display. Not done.
Created version.h, now support a version extension string for
distributors who patch heavily. Henceforth release engineer should
change the version in version.h not version.c.
permissions on /dev/null. Exempt it from some checks.
Reported by Andreas M. Kirchwitz.
+PP/03 Report version information for many libraries, including
+ Exim version information for dynamically loaded libraries. Created
+ version.h, now support a version extension string for distributors
+ who patch heavily. Dynamic module ABI change.
+
Exim version 4.73
-----------------
ln -s ../src/store.h store.h
ln -s ../src/structs.h structs.h
ln -s ../src/lookupapi.h lookupapi.h
+ln -s ../src/version.h version.h
ln -s ../src/acl.c acl.c
ln -s ../src/buildconfig.c buildconfig.c
#------------------------------------------------------------------------------
# See below for dynamic lookup modules.
# LOOKUP_MODULE_DIR=/usr/lib/exim/lookups/
+# If not using package management but using this anyway, then think about how
+# you perform upgrades and revert them. You should consider the benefit of
+# embedding the Exim version number into LOOKUP_MODULE_DIR, so that you can
+# maintain two concurrent sets of modules.
# To build a module dynamically, you'll need to define CFLAGS_DYNAMIC for
# your platform. Eg:
return 0; /* Stop compiler complaints */
}
+/*************************************************
+* Diagnostic API *
+*************************************************/
+
+void
+auth_cyrus_sasl_version_report(FILE *f)
+{
+ const char *implementation, *version;
+ sasl_version_info(&implementation, &version, NULL, NULL, NULL, NULL);
+ fprintf(f, "Library version: Cyrus SASL: Compile: %d.%d.%d\n"
+ " Runtime: %s [%s]\n",
+ SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
+ version, implementation);
+}
+
/*************************************************
* Client entry point *
*************************************************/
lookup_info **lookup_list;
int lookup_list_count = 0;
+static int lookup_list_init_done = 0;
+
/* Table of information about all possible authentication mechamisms. All
entries are always present if any mechanism is declared, but the functions are
set to NULL for those that are not compiled into the binary. */
int moduleerrors = 0;
struct lookupmodulestr *p;
+ if (lookup_list_init_done)
+ return;
+ lookup_list_init_done = 1;
+
#if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
extern lookup_module_info cdb_lookup_module_info;
addlookupmodule(NULL, &cdb_lookup_module_info);
#include "exim.h"
+extern void init_lookup_list(void);
+
/*************************************************
#ifdef SUPPORT_TLS
tls_version_report(f);
#endif
+
+/* Everything else is details which are only worth reporting when debugging.
+Perhaps the tls_version_report should move into this too. */
+DEBUG(D_any) do {
+
+ int i;
+
+#ifdef AUTH_CYRUS_SASL
+ auth_cyrus_sasl_version_report(f);
+#endif
+
+ fprintf(f, "Library version: PCRE: Compile: %d.%d%s\n"
+ " Runtime: %s\n",
+ PCRE_MAJOR, PCRE_MINOR,
+ /* PRE_PRERELEASE is either defined and empty or a string.
+ * This should work: */
+ PCRE_PRERELEASE "",
+ pcre_version());
+
+ init_lookup_list();
+ for (i = 0; i < lookup_list_count; i++)
+ {
+ if (lookup_list[i]->version_report)
+ lookup_list[i]->version_report(f);
+ }
+
+} while (0);
}
debug_printf("Exim version %s uid=%ld gid=%ld pid=%d D=%x\n",
version_string, (long int)real_uid, (long int)real_gid, (int)getpid(),
debug_selector);
- show_whats_supported(stderr);
+ if (!version_printed)
+ show_whats_supported(stderr);
}
}
}
#endif /* EXIM_PERL */
-/* Initialise lookup_list */
-extern void init_lookup_list(void);
+/* Initialise lookup_list
+If debugging, already called above via version reporting.
+This does mean that debugging causes the list to be initialised while root.
+This *should* be harmless -- all modules are loaded from a fixed dir and
+it's code that would, if not a module, be part of Exim already. */
init_lookup_list();
/* Log the arguments of the call if the configuration file said so. This is
#endif
#endif
+/* These are for reporting version information from various componenents, to
+figure out what's actually happening. They need to be available to the main
+function, so we declare them here. Unfortunate. */
+
+#ifdef AUTH_CYRUS_SASL
+extern void auth_cyrus_sasl_version_report(FILE *);
+#endif
/* End of exim.h */
uschar *(*quote)( /* quoting function */
uschar *, /* string to quote */
uschar *); /* additional data from quote name */
+ void (*version_report)( /* diagnostic function */
+ FILE *); /* fh to write to */
} lookup_info;
/* This magic number is used by the following lookup_module_info structure
- for checking API compatibility. It's equivalent to the string"LMM1" */
-#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4d31
+ for checking API compatibility. It's equivalent to the string"LMM2" */
+#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4d32
+/* Version 2 adds: version_report */
typedef struct lookup_module_info {
uint magic;
Each lookup type is implemented by 6 functions, xxx_open(), xxx_check(),
xxx_find(), xxx_close(), xxx_tidy(), and xxx_quote(), where xxx is the name of
-the lookup type (e.g. lsearch, dbm, or whatever).
+the lookup type (e.g. lsearch, dbm, or whatever). In addition, there is
+a version reporting function used to trace compile-vs-runtime conflicts and
+to help administrators ensure that the modules from the correct build are
+in use by the main binary.
The xxx_check(), xxx_close(), xxx_tidy(), and xxx_quote() functions need not
exist. There is a table in drtables.c which links the lookup names to the
does NOT use the POOL_SEARCH store, because it's usually never called from any
lookup code.
+xxx_report_version()
+--------------------
+
+This is called to report diagnostic information to a file stream.
+Typically it would report both compile-time and run-time version information.
+The arguments are:
+
+ FILE *stream where to fprintf() the data to
+
+
****
(void)close(cdbp->fileno);
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+cdb_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: CDB: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
lookup_info cdb_lookup_info = {
US"cdb", /* lookup name */
lookup_absfile, /* uses absolute file name */
cdb_find, /* find function */
cdb_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ cdb_version_report /* version reporting */
};
#ifdef DYNLOOKUP
EXIM_DBCLOSE((EXIM_DB *)handle);
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+dbm_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: DBM: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
lookup_info dbm_lookup_info = {
US"dbm", /* lookup name */
lookup_absfile, /* uses absolute file name */
dbmdb_find, /* find function */
dbmdb_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ dbm_version_report /* version reporting */
};
lookup_info dbmz_lookup_info = {
dbmnz_find, /* find function */
dbmdb_close, /* sic */ /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ NULL /* no version reporting (redundant) */
};
#ifdef DYNLOOKUP
return OK;
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+dnsdb_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: DNSDB: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"dnsdb", /* lookup name */
lookup_querystyle, /* query style */
dnsdb_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ dnsdb_version_report /* version reporting */
};
#ifdef DYNLOOKUP
handle = handle; /* Avoid compiler warning */
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+dsearch_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: dsearch: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"dsearch", /* lookup name */
lookup_absfile, /* uses absolute file name */
dsearch_find, /* find function */
dsearch_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ dsearch_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+ibase_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: ibase: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"ibase", /* lookup name */
lookup_querystyle, /* query-style lookup */
ibase_find, /* find function */
NULL, /* no close function */
ibase_tidy, /* tidy function */
- ibase_quote /* quoting function */
+ ibase_quote, /* quoting function */
+ ibase_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+ldap_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: LDAP: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info ldap_lookup_info = {
US"ldap", /* lookup name */
lookup_querystyle, /* query-style lookup */
eldap_find, /* find function */
NULL, /* no close function */
eldap_tidy, /* tidy function */
- eldap_quote /* quoting function */
+ eldap_quote, /* quoting function */
+ ldap_version_report /* version reporting */
};
static lookup_info ldapdn_lookup_info = {
eldapdn_find, /* find function */
NULL, /* no close function */
eldap_tidy, /* sic */ /* tidy function */
- eldap_quote /* sic */ /* quoting function */
+ eldap_quote, /* sic */ /* quoting function */
+ NULL /* no version reporting (redundant) */
};
static lookup_info ldapm_lookup_info = {
eldapm_find, /* find function */
NULL, /* no close function */
eldap_tidy, /* sic */ /* tidy function */
- eldap_quote /* sic */ /* quoting function */
+ eldap_quote, /* sic */ /* quoting function */
+ NULL /* no version reporting (redundant) */
};
#ifdef DYNLOOKUP
(void)fclose((FILE *)handle);
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+lsearch_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: lsearch: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info iplsearch_lookup_info = {
US"iplsearch", /* lookup name */
lookup_absfile, /* uses absolute file name */
iplsearch_find, /* find function */
lsearch_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ NULL /* no version reporting (redundant) */
};
static lookup_info lsearch_lookup_info = {
lsearch_find, /* find function */
lsearch_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ lsearch_version_report /* version reporting */
};
static lookup_info nwildlsearch_lookup_info = {
nwildlsearch_find, /* find function */
lsearch_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ NULL /* no version reporting (redundant) */
};
static lookup_info wildlsearch_lookup_info = {
wildlsearch_find, /* find function */
lsearch_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ NULL /* no version reporting (redundant) */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+mysql_version_report(FILE *f)
+{
+fprintf(f, "Library version: MySQL: Compile: %s [%s]\n"
+ " Runtime: %s\n",
+ MYSQL_SERVER_VERSION, MYSQL_COMPILATION_COMMENT,
+ mysql_get_client_info());
+#ifdef DYNLOOKUP
+fprintf(f, " Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
/* These are the lookup_info blocks for this driver */
static lookup_info mysql_lookup_info = {
mysql_find, /* find function */
NULL, /* no close function */
mysql_tidy, /* tidy function */
- mysql_quote /* quoting function */
+ mysql_quote, /* quoting function */
+ mysql_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return (rc == YPERR_KEY || rc == YPERR_MAP)? FAIL : DEFER;
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+nis_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: NIS: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info nis_lookup_info = {
US"nis", /* lookup name */
0, /* not abs file, not query style*/
nis_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ nis_version_report /* version reporting */
};
static lookup_info nis0_lookup_info = {
nis0_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ NULL /* no version reporting (redundant) */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+nisplus_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: NIS+: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"nisplus", /* lookup name */
lookup_querystyle, /* query-style lookup */
nisplus_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- nisplus_quote /* quoting function */
+ nisplus_quote, /* quoting function */
+ nisplus_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+oracle_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: Oracle: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"oracle", /* lookup name */
lookup_querystyle, /* query-style lookup */
oracle_find, /* find function */
NULL, /* no close function */
oracle_tidy, /* tidy function */
- oracle_quote /* quoting function */
+ oracle_quote, /* quoting function */
+ oracle_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return OK;
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+passwd_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: passwd: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
static lookup_info _lookup_info = {
US"passwd", /* lookup name */
lookup_querystyle, /* query-style lookup */
passwd_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ passwd_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+pgsql_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: PostgreSQL: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+
+/* Version reporting: there appears to be no available information about
+the client library in libpq-fe.h; once you have a connection object, you
+can access the server version and the chosen protocol version, but those
+aren't really what we want. It might make sense to debug_printf those
+when the connection is established though? */
+}
+
+
static lookup_info _lookup_info = {
US"pgsql", /* lookup name */
lookup_querystyle, /* query-style lookup */
pgsql_find, /* find function */
NULL, /* no close function */
pgsql_tidy, /* tidy function */
- pgsql_quote /* quoting function */
+ pgsql_quote, /* quoting function */
+ pgsql_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return OK;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+spf_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: SPF: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"spf", /* lookup name */
0, /* not absfile, not query style */
spf_find, /* find function */
spf_close, /* close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ spf_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return quoted;
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+sqlite_version_report(FILE *f)
+{
+fprintf(f, "Library version: SQLite: Compile: %s\n"
+ " Runtime: %s\n",
+ SQLITE_VERSION, sqlite3_libversion());
+#ifdef DYNLOOKUP
+fprintf(f, " Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
static lookup_info _lookup_info = {
US"sqlite", /* lookup name */
lookup_absfilequery, /* query-style lookup, starts with file name */
sqlite_find, /* find function */
sqlite_close, /* close function */
NULL, /* no tidy function */
- sqlite_quote /* quoting function */
+ sqlite_quote, /* quoting function */
+ sqlite_version_report /* version reporting */
};
#ifdef DYNLOOKUP
return OK;
}
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+testdb_version_report(FILE *f)
+{
+#ifdef DYNLOOKUP
+fprintf(f, "Library version: TestDB: Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
+
static lookup_info _lookup_info = {
US"testdb", /* lookup name */
lookup_querystyle, /* query-style lookup */
testdb_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ testdb_version_report /* version reporting */
};
#ifdef DYNLOOKUP
}
}
+
+
+/*************************************************
+* Version reporting entry point *
+*************************************************/
+
+/* See local README for interface description. */
+
+#include "../version.h"
+
+void
+whoson_version_report(FILE *f)
+{
+fprintf(f, "Library version: Whoson: Runtime: %s\n", wso_version());
+#ifdef DYNLOOKUP
+fprintf(f, " Exim version %s\n", EXIM_VERSION_STR);
+#endif
+}
+
static lookup_info _lookup_info = {
US"whoson", /* lookup name */
lookup_querystyle, /* query-style lookup */
whoson_find, /* find function */
NULL, /* no close function */
NULL, /* no tidy function */
- NULL /* no quoting function */
+ NULL, /* no quoting function */
+ whoson_version_report /* version reporting */
};
#ifdef DYNLOOKUP
#include "exim.h"
-
-#define THIS_VERSION "4.73"
+#include "version.h"
/* The header file cnumber.h contains a single line containing the
version_cnumber = cnumber_buffer;
version_cnumber_format = US"%d\0<<eximcnumber>>";
sprintf(CS version_cnumber, CS version_cnumber_format, cnumber);
-version_string = US THIS_VERSION "\0<<eximversion>>";
+version_string = US EXIM_VERSION_STR "\0<<eximversion>>";
Ustrcpy(today, __DATE__);
if (today[4] == ' ') today[4] = '0';
--- /dev/null
+/*************************************************
+* Exim - an Internet mail transport agent *
+*************************************************/
+
+/* Copyright (c) Google, Inc. 2010 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* This is bumped by the Exim Maintainers, the release engineer: */
+#define EXIM_RELEASE_VERSION_STR "4.73"
+/* If you apply extensive local patches, consider putting -foo into here */
+#define EXIM_VARIANT_VERSION ""
+
+#define EXIM_VERSION_STR EXIM_RELEASE_VERSION_STR EXIM_VARIANT_VERSION
+
+/* End of version.h */