segv_handler(int sig, siginfo_t * info, void * uctx)
{
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (fault address: %p)", info->si_addr);
+# if defined(SEGV_MAPERR) && defined(SEGV_ACCERR) && defined(SEGV_BNDERR) && defined(SEGV_PKUERR)
switch (info->si_code)
{
case SEGV_MAPERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_MAPERR"); break;
case SEGV_BNDERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_BNDERR"); break;
case SEGV_PKUERR: log_write(0, LOG_MAIN|LOG_PANIC, "SEGV_PKUERR"); break;
}
+# endif
if (US info->si_addr < US 4096)
log_write(0, LOG_MAIN|LOG_PANIC, "SIGSEGV (null pointer indirection)");
else
int rc = verify_address(deliver_make_addr(address,TRUE), stdout, flags, -1,
-1, -1, NULL, NULL, NULL);
if (rc == FAIL) *exit_value = 2;
- else if (rc == DEFER && *exit_value == 0) *exit_value = 1;
+ else if (rc == DEFER && *exit_value == 0) *exit_value = 1;
}
}
*************************************************/
static void
-show_db_version(FILE * f)
+show_string(BOOL is_stdout, gstring * g)
+{
+const uschar * s = string_from_gstring(g);
+if (s)
+ if (is_stdout) fputs(CCS s, stdout);
+ else debug_printf("%s", s);
+}
+
+
+static gstring *
+show_db_version(gstring * g)
{
#ifdef DB_VERSION_STRING
DEBUG(D_any)
{
- fprintf(f, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING);
- fprintf(f, " Runtime: %s\n",
+ g = string_fmt_append(g, "Library version: BDB: Compile: %s\n", DB_VERSION_STRING);
+ g = string_fmt_append(g, " Runtime: %s\n",
db_version(NULL, NULL, NULL));
}
else
- fprintf(f, "Berkeley DB: %s\n", DB_VERSION_STRING);
+ g = string_fmt_append(g, "Berkeley DB: %s\n", DB_VERSION_STRING);
#elif defined(BTREEVERSION) && defined(HASHVERSION)
- #ifdef USE_DB
- fprintf(f, "Probably Berkeley DB version 1.8x (native mode)\n");
- #else
- fprintf(f, "Probably Berkeley DB version 1.8x (compatibility mode)\n");
- #endif
+# ifdef USE_DB
+ g = string_cat(g, US"Probably Berkeley DB version 1.8x (native mode)\n");
+# else
+ g = string_cat(g, US"Probably Berkeley DB version 1.8x (compatibility mode)\n");
+# endif
#elif defined(_DBM_RDONLY) || defined(dbm_dirfno)
-fprintf(f, "Probably ndbm\n");
+g = string_cat(g, US"Probably ndbm\n");
#elif defined(USE_TDB)
-fprintf(f, "Using tdb\n");
+g = string_cat(g, US"Using tdb\n");
#else
- #ifdef USE_GDBM
- fprintf(f, "Probably GDBM (native mode)\n");
- #else
- fprintf(f, "Probably GDBM (compatibility mode)\n");
- #endif
+# ifdef USE_GDBM
+ g = string_cat(g, US"Probably GDBM (native mode)\n");
+# else
+ g = string_cat(g, US"Probably GDBM (compatibility mode)\n");
+# endif
#endif
+return g;
}
/* This function is called for -bV/--version and for -d to output the optional
features of the current Exim binary.
-Arguments: a FILE for printing
+Arguments: BOOL, true for stdout else debug channel
Returns: nothing
*/
static void
-show_whats_supported(FILE * fp)
+show_whats_supported(BOOL is_stdout)
{
rmark reset_point = store_mark();
-gstring * g;
-DEBUG(D_any) {} else show_db_version(fp);
+gstring * g = NULL;
+
+DEBUG(D_any) {} else g = show_db_version(g);
-g = string_cat(NULL, US"Support for:");
+g = string_cat(g, US"Support for:");
#ifdef SUPPORT_CRYPTEQ
g = string_cat(g, US" crypteq");
#endif
#ifdef EXPERIMENTAL_QUEUEFILE
g = string_cat(g, US" Experimental_QUEUEFILE");
#endif
-#if defined(EXPERIMENTAL_SRS_ALT)
- g = string_cat(g, US" Experimental_SRS");
-#endif
g = string_cat(g, US"\n");
g = string_cat(g, US"Lookups (built-in):");
#ifdef WITH_CONTENT_SCAN
g = malware_show_supported(g);
#endif
+show_string(is_stdout, g); g = NULL;
if (fixed_never_users[0] > 0)
{
}
g = string_fmt_append(g, "Configure owner: %d:%d\n", config_uid, config_gid);
-fputs(CS string_from_gstring(g), fp);
-fprintf(fp, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
+g = string_fmt_append(g, "Size of off_t: " SIZE_T_FMT "\n", sizeof(off_t));
/* 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 {
+DEBUG(D_any)
+ {
/* clang defines __GNUC__ (at least, for me) so test for it first */
#if defined(__clang__)
- fprintf(fp, "Compiler: CLang [%s]\n", __clang_version__);
+ g = string_fmt_append(g, "Compiler: CLang [%s]\n", __clang_version__);
#elif defined(__GNUC__)
- fprintf(fp, "Compiler: GCC [%s]\n",
+ g = string_fmt_append(g, "Compiler: GCC [%s]\n",
# ifdef __VERSION__
__VERSION__
# else
# endif
);
#else
- fprintf(fp, "Compiler: <unknown>\n");
+ g = string_cat(g, US"Compiler: <unknown>\n");
#endif
#if defined(__GLIBC__) && !defined(__UCLIBC__)
- fprintf(fp, "Library version: Glibc: Compile: %d.%d\n",
+ g = string_fmt_append(g, "Library version: Glibc: Compile: %d.%d\n",
__GLIBC__, __GLIBC_MINOR__);
if (__GLIBC_PREREQ(2, 1))
- fprintf(fp, " Runtime: %s\n",
+ g = string_fmt_append(g, " Runtime: %s\n",
gnu_get_libc_version());
#endif
-show_db_version(fp);
+g = show_db_version(g);
#ifndef DISABLE_TLS
- tls_version_report(fp);
+ g = tls_version_report(g);
#endif
#ifdef SUPPORT_I18N
- utf8_version_report(fp);
+ g = utf8_version_report(g);
#endif
#ifdef SUPPORT_DMARC
- dmarc_version_report(fp);
+ g = dmarc_version_report(g);
#endif
#ifdef SUPPORT_SPF
- spf_lib_version_report(fp);
+ g = spf_lib_version_report(g);
#endif
- for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
- if (authi->version_report)
- (*authi->version_report)(fp);
+show_string(is_stdout, g);
+g = NULL;
+
+for (auth_info * authi = auths_available; *authi->driver_name != '\0'; ++authi)
+ if (authi->version_report)
+ g = (*authi->version_report)(g);
/* PCRE_PRERELEASE is either defined and empty or a bare sequence of
characters; unless it's an ancient version of PCRE in which case it
{
uschar buf[24];
pcre2_config(PCRE2_CONFIG_VERSION, buf);
- fprintf(fp, "Library version: PCRE2: Compile: %d.%d%s\n"
+ g = string_fmt_append(g, "Library version: PCRE2: Compile: %d.%d%s\n"
" Runtime: %s\n",
PCRE2_MAJOR, PCRE2_MINOR,
EXPAND_AND_QUOTE(PCRE2_PRERELEASE) "",
#undef QUOTE
#undef EXPAND_AND_QUOTE
- init_lookup_list();
- for (int i = 0; i < lookup_list_count; i++)
- if (lookup_list[i]->version_report)
- lookup_list[i]->version_report(fp);
+show_string(is_stdout, g);
+g = NULL;
+
+init_lookup_list();
+for (int i = 0; i < lookup_list_count; i++)
+ if (lookup_list[i]->version_report)
+ g = lookup_list[i]->version_report(g);
+show_string(is_stdout, g);
+g = NULL;
#ifdef WHITELIST_D_MACROS
- fprintf(fp, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
+ g = string_fmt_append(g, "WHITELIST_D_MACROS: \"%s\"\n", WHITELIST_D_MACROS);
#else
- fprintf(fp, "WHITELIST_D_MACROS unset\n");
+ g = string_cat(g, US"WHITELIST_D_MACROS unset\n");
#endif
#ifdef TRUSTED_CONFIG_LIST
- fprintf(fp, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST);
+ g = string_fmt_append(g, "TRUSTED_CONFIG_LIST: \"%s\"\n", TRUSTED_CONFIG_LIST);
#else
- fprintf(fp, "TRUSTED_CONFIG_LIST unset\n");
+ g = string_cat(g, US"TRUSTED_CONFIG_LIST unset\n");
#endif
+ }
-} while (0);
+show_string(is_stdout, g);
store_reset(reset_point);
}
get_stdinput(char *(*fn_readline)(const char *), void(*fn_addhist)(const char *))
{
gstring * g = NULL;
+BOOL had_input = FALSE;
if (!fn_readline) { printf("> "); fflush(stdout); }
for (int i = 0;; i++)
{
uschar buffer[1024];
- uschar *p, *ss;
+ uschar * p, * ss;
- #ifdef USE_READLINE
+#ifdef USE_READLINE
char *readline_line = NULL;
if (fn_readline)
{
if (!(readline_line = fn_readline((i > 0)? "":"> "))) break;
- if (*readline_line != 0 && fn_addhist) fn_addhist(readline_line);
+ if (*readline_line && fn_addhist) fn_addhist(readline_line);
p = US readline_line;
}
else
- #endif
+#endif
/* readline() not in use */
{
- if (Ufgets(buffer, sizeof(buffer), stdin) == NULL) break;
+ if (Ufgets(buffer, sizeof(buffer), stdin) == NULL) break; /*EOF*/
p = buffer;
}
/* Handle the line */
- ss = p + (int)Ustrlen(p);
- while (ss > p && isspace(ss[-1])) ss--;
+ had_input = TRUE;
+ ss = p + Ustrlen(p);
+ while (ss > p && isspace(ss[-1])) ss--; /* strip trailing newline (and spaces) */
if (i > 0)
- while (p < ss && isspace(*p)) p++; /* leading space after cont */
+ while (p < ss && isspace(*p)) p++; /* strip leading space after cont */
g = string_catn(g, p, ss - p);
- #ifdef USE_READLINE
+#ifdef USE_READLINE
if (fn_readline) free(readline_line);
- #endif
+#endif
/* g can only be NULL if ss==p */
- if (ss == p || g->s[g->ptr-1] != '\\')
+ if (ss == p || g->s[g->ptr-1] != '\\') /* not continuation; done */
break;
- --g->ptr;
- (void) string_from_gstring(g);
+ --g->ptr; /* drop the \ */
}
-if (!g) printf("\n");
-return string_from_gstring(g);
+if (had_input) return g ? string_from_gstring(g) : US"";
+printf("\n");
+return NULL;
}
int list_queue_option = 0;
int msg_action = 0;
int msg_action_arg = -1;
-int namelen = (argv[0] == NULL)? 0 : Ustrlen(argv[0]);
+int namelen = argv[0] ? Ustrlen(argv[0]) : 0;
int queue_only_reason = 0;
#ifdef EXIM_PERL
int perl_start_option = 0;
debug_store = TRUE;
/* Protect against abusive argv[0] */
+if (!argv[0] || !argc) exim_fail("exim: executable name required\n");
exim_str_fail_toolong(argv[0], PATH_MAX, "argv[0]");
/* The C standard says that the equivalent of setlocale(LC_ALL, "C") is obeyed
version_cnumber, version_date);
printf("%s\n", CS version_copyright);
version_printed = TRUE;
- show_whats_supported(stdout);
+ show_whats_supported(TRUE);
f.log_testing_mode = TRUE;
}
else badarg = TRUE;
#endif
break;
- /* -d: Set debug level (see also -v below) or set the drop_cr option.
- The latter is now a no-op, retained for compatibility only. If -dd is used,
- debugging subprocesses of the daemon is disabled. */
-
case 'd':
+
+ /* -dropcr: Set this option. Now a no-op, retained for compatibility only. */
+
if (Ustrcmp(argrest, "ropcr") == 0)
{
/* drop_cr = TRUE; */
}
- /* Use an intermediate variable so that we don't set debugging while
- decoding the debugging bits. */
+ /* -dp: Set up a debug pretrigger buffer with given size. */
+
+ else if (Ustrcmp(argrest, "p") == 0)
+ if (++i >= argc)
+ badarg = TRUE;
+ else
+ debug_pretrigger_setup(argv[i]);
+
+ /* -dt: Set a debug trigger selector */
+
+ else if (Ustrncmp(argrest, "t=", 2) == 0)
+ dtrigger_selector = (unsigned int) Ustrtol(argrest + 2, NULL, 0);
+
+ /* -d: Set debug level (see also -v below).
+ If -dd is used, debugging subprocesses of the daemon is disabled. */
else
{
+ /* Use an intermediate variable so that we don't set debugging while
+ decoding the debugging bits. */
+
unsigned int selector = D_default;
debug_selector = 0;
debug_file = NULL;
version_string, (long int)real_uid, (long int)real_gid, (int)getpid(),
debug_selector);
if (!version_printed)
- show_whats_supported(stderr);
+ show_whats_supported(FALSE);
}
}