*************************************************/
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
+/* Copyright (c) The Exim Maintainers 2020 - 2021 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for writing log files. The code for maintaining datestamped
Ustrcpy(mainlog_name, buffer);
if (string_datestamp_offset > 0)
mainlog_datestamp = mainlog_name + string_datestamp_offset;
+ break;
+
case lt_reject:
/* Ditto for the reject log */
Ustrcpy(rejectlog_name, buffer);
if (string_datestamp_offset > 0)
rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
+ break;
+
case lt_debug:
/* and deal with the debug log (which keeps the datestamp, but does not
update it) */
if (ok2)
Ustrcpy(debuglog_name, buffer);
}
+ break;
+
default:
/* Remove any datestamp if this is the panic log. This is rare, so there's no
need to optimize getting the datestamp length. We remove one non-alphanumeric
due to overlap we must use memmove() not Ustrcpy(). */
memmove(from, to, Ustrlen(to)+1);
}
+ break;
}
/* If the file name is too long, it is an unrecoverable disaster */
/* We now have the file name. After a successful open, return. */
-*fd = log_open_as_exim(buffer);
-
-if (*fd >= 0)
- {
+if ((*fd = log_open_as_exim(buffer)) >= 0)
return;
- }
euid = geteuid();
}
-void
-set_file_path(BOOL *multiple)
+
+static void
+set_file_path(void)
{
-uschar *s;
int sep = ':'; /* Fixed separator - outside use */
-const uschar *ss = *log_file_path ? log_file_path : US LOG_FILE_PATH;
-
-logging_mode = 0;
-while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
+uschar *t;
+const uschar *tt = US LOG_FILE_PATH;
+while ((t = string_nextinlist(&tt, &sep, log_buffer, LOG_BUFFER_SIZE)))
{
- if (Ustrcmp(s, "syslog") == 0)
- logging_mode |= LOG_MODE_SYSLOG;
- else if (logging_mode & LOG_MODE_FILE) /* we know a file already */
- {
- if (multiple) *multiple = TRUE;
- }
- else
- {
- logging_mode |= LOG_MODE_FILE;
-
- /* If a non-empty path is given, use it */
-
- if (*s)
- file_path = string_copy(s);
-
- /* If the path is empty, we want to use the first non-empty, non-
- syslog item in LOG_FILE_PATH, if there is one, since the value of
- log_file_path may have been set at runtime. If there is no such item,
- use the ultimate default in the spool directory. */
- }
+ if (Ustrcmp(t, "syslog") == 0 || t[0] == 0) continue;
+ file_path = string_copy(t);
+ break;
}
}
void
mainlog_close(void)
{
-/* avoid closing it if it is closed already or if we do not see a chance
-to open the file mainlog later again */
-if (mainlogfd < 0 /* already closed */
- || !(geteuid() == 0 || geteuid() == exim_uid))
- return;
+if (mainlogfd < 0) return;
(void)close(mainlogfd);
mainlogfd = -1;
mainlog_inode = 0;
/* If nothing has been set, don't waste effort... the default values for the
statics are file_path="" and logging_mode = LOG_MODE_FILE. */
- if (*log_file_path) set_file_path(&multiple);
+ if (*log_file_path)
+ {
+ int sep = ':'; /* Fixed separator - outside use */
+ uschar *s;
+ const uschar *ss = log_file_path;
+
+ logging_mode = 0;
+ while ((s = string_nextinlist(&ss, &sep, log_buffer, LOG_BUFFER_SIZE)))
+ {
+ if (Ustrcmp(s, "syslog") == 0)
+ logging_mode |= LOG_MODE_SYSLOG;
+ else if (logging_mode & LOG_MODE_FILE)
+ multiple = TRUE;
+ else
+ {
+ logging_mode |= LOG_MODE_FILE;
+
+ /* If a non-empty path is given, use it */
+
+ if (*s)
+ file_path = string_copy(s);
+
+ /* If the path is empty, we want to use the first non-empty, non-
+ syslog item in LOG_FILE_PATH, if there is one, since the value of
+ log_file_path may have been set at runtime. If there is no such item,
+ use the ultimate default in the spool directory. */
+
+ else
+ set_file_path(); /* Empty item in log_file_path */
+ } /* First non-syslog item in log_file_path */
+ } /* Scan of log_file_path */
+ }
/* If no modes have been selected, it is a major disaster */
"More than one path given in log_file_path: using %s", file_path);
}
+/* Optionally trigger debug */
+
+if (flags & LOG_PANIC && dtrigger_selector & BIT(DTi_panictrigger))
+ debug_trigger_fire();
+
/* If debugging, show all log entries, but don't show headers. Do it all
in one go so that it doesn't get split when multi-processing. */
The first use of this is in ACL logic, "control = debug/tag=foo/opts=+expand"
which can be combined with conditions, etc, to activate extra logging only
-for certain sources. The second use is inetd wait mode debug preservation. */
+for certain sources. The second use is inetd wait mode debug preservation.
+
+It might be nice, in ACL-initiated pretrigger mode, to not create the file
+immediately but only upon a trigger - but we'd need another cmdline option
+to pass the name through child_exxec_exim(). */
void
debug_logging_activate(uschar *tag_name, uschar *opts)
{
-int fd = -1;
-
if (debug_file)
{
debug_printf("DEBUGGING ACTIVATED FROM WITHIN CONFIG.\n"
return;
}
-if (tag_name != NULL && (Ustrchr(tag_name, '/') != NULL))
+if (tag_name && (Ustrchr(tag_name, '/') != NULL))
{
log_write(0, LOG_MAIN|LOG_PANIC, "debug tag may not contain a '/' in: %s",
tag_name);
resulting in certain setup not having been done. Hack this for now so we
do not segfault; note that nondefault log locations will not work */
-if (!*file_path) set_file_path(NULL);
+if (!*file_path) set_file_path();
-open_log(&fd, lt_debug, tag_name);
+open_log(&debug_fd, lt_debug, tag_name);
-if (fd != -1)
- debug_file = fdopen(fd, "w");
+if (debug_fd != -1)
+ debug_file = fdopen(debug_fd, "w");
else
log_write(0, LOG_MAIN|LOG_PANIC, "unable to open debug log");
}
void
-debug_logging_stop(void)
+debug_logging_stop(BOOL kill)
{
+debug_pretrigger_discard();
if (!debug_file || !debuglog_name[0]) return;
debug_selector = 0;
fclose(debug_file);
debug_file = NULL;
-unlink_log(lt_debug);
+debug_fd = -1;
+if (kill) unlink_log(lt_debug);
}
-void
-open_logs(void)
-{
-set_file_path(NULL);
-open_log(&mainlogfd, lt_main, 0);
-open_log(&rejectlogfd, lt_reject, 0);
-}
/* End of log.c */