aboutsummaryrefslogtreecommitdiff
path: root/src/lib/log/log.c
diff options
context:
space:
mode:
authorGeorge Kadianakis <desnacked@riseup.net>2019-09-12 18:09:35 +0300
committerGeorge Kadianakis <desnacked@riseup.net>2019-09-12 18:09:35 +0300
commit028733e8b6f36bae420b1e41897401fa3b14ccf8 (patch)
treec1b3929dad5011875d5b8e6ee9caea0514733f9c /src/lib/log/log.c
parent3aaa4d416beee81eba3fed1ce9eda17e686fed52 (diff)
parentebce7059ffbc3a4a8b7ff7cf923b0e6a402f4f33 (diff)
downloadtor-028733e8b6f36bae420b1e41897401fa3b14ccf8.tar.gz
tor-028733e8b6f36bae420b1e41897401fa3b14ccf8.zip
Merge branch 'tor-github/pr/1303'
Diffstat (limited to 'src/lib/log/log.c')
-rw-r--r--src/lib/log/log.c85
1 files changed, 74 insertions, 11 deletions
diff --git a/src/lib/log/log.c b/src/lib/log/log.c
index 56f016eae4..be6f459554 100644
--- a/src/lib/log/log.c
+++ b/src/lib/log/log.c
@@ -225,6 +225,7 @@ int log_global_min_severity_ = LOG_NOTICE;
static void delete_log(logfile_t *victim);
static void close_log(logfile_t *victim);
+static void close_log_sigsafe(logfile_t *victim);
static char *domain_to_string(log_domain_mask_t domain,
char *buf, size_t buflen);
@@ -665,13 +666,24 @@ tor_log_update_sigsafe_err_fds(void)
const logfile_t *lf;
int found_real_stderr = 0;
- int fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ /* log_fds and err_fds contain matching entries: log_fds are the fds used by
+ * the log module, and err_fds are the fds used by the err module.
+ * For stdio logs, the log_fd and err_fd values are identical,
+ * and the err module closes the fd on shutdown.
+ * For file logs, the err_fd is a dup() of the log_fd,
+ * and the log and err modules both close their respective fds on shutdown.
+ * (Once all fds representing a file are closed, the underlying file is
+ * closed.)
+ */
+ int log_fds[TOR_SIGSAFE_LOG_MAX_FDS];
+ int err_fds[TOR_SIGSAFE_LOG_MAX_FDS];
int n_fds;
LOCK_LOGS();
/* Reserve the first one for stderr. This is safe because when we daemonize,
- * we dup2 /dev/null to stderr, */
- fds[0] = STDERR_FILENO;
+ * we dup2 /dev/null to stderr.
+ * For stderr, log_fds and err_fds are the same. */
+ log_fds[0] = err_fds[0] = STDERR_FILENO;
n_fds = 1;
for (lf = logfiles; lf; lf = lf->next) {
@@ -685,25 +697,39 @@ tor_log_update_sigsafe_err_fds(void)
(LD_BUG|LD_GENERAL)) {
if (lf->fd == STDERR_FILENO)
found_real_stderr = 1;
- /* Avoid duplicates */
- if (int_array_contains(fds, n_fds, lf->fd))
+ /* Avoid duplicates by checking the log module fd against log_fds */
+ if (int_array_contains(log_fds, n_fds, lf->fd))
continue;
- fds[n_fds++] = lf->fd;
+ /* Update log_fds using the log module's fd */
+ log_fds[n_fds] = lf->fd;
+ if (lf->needs_close) {
+ /* File log fds are duplicated, because close_log() closes the log
+ * module's fd, and tor_log_close_sigsafe_err_fds() closes the err
+ * module's fd. Both refer to the same file. */
+ err_fds[n_fds] = dup(lf->fd);
+ } else {
+ /* stdio log fds are not closed by the log module.
+ * tor_log_close_sigsafe_err_fds() closes stdio logs. */
+ err_fds[n_fds] = lf->fd;
+ }
+ n_fds++;
if (n_fds == TOR_SIGSAFE_LOG_MAX_FDS)
break;
}
}
if (!found_real_stderr &&
- int_array_contains(fds, n_fds, STDOUT_FILENO)) {
+ int_array_contains(log_fds, n_fds, STDOUT_FILENO)) {
/* Don't use a virtual stderr when we're also logging to stdout. */
raw_assert(n_fds >= 2); /* Don't tor_assert inside log fns */
- fds[0] = fds[--n_fds];
+ --n_fds;
+ log_fds[0] = log_fds[n_fds];
+ err_fds[0] = err_fds[n_fds];
}
UNLOCK_LOGS();
- tor_log_set_sigsafe_err_fds(fds, n_fds);
+ tor_log_set_sigsafe_err_fds(err_fds, n_fds);
}
/** Add to <b>out</b> a copy of every currently configured log file name. Used
@@ -809,6 +835,30 @@ logs_free_all(void)
* that happened between here and the end of execution. */
}
+/** Close signal-safe log files.
+ * Closing the log files makes the process and OS flush log buffers.
+ *
+ * This function is safe to call from a signal handler. It should only be
+ * called when shutting down the log or err modules. It is currenly called
+ * by the err module, when terminating the process on an abnormal condition.
+ */
+void
+logs_close_sigsafe(void)
+{
+ logfile_t *victim, *next;
+ /* We can't LOCK_LOGS() in a signal handler, because it may call
+ * signal-unsafe functions. And we can't deallocate memory, either. */
+ next = logfiles;
+ logfiles = NULL;
+ while (next) {
+ victim = next;
+ next = next->next;
+ if (victim->needs_close) {
+ close_log_sigsafe(victim);
+ }
+ }
+}
+
/** Remove and free the log entry <b>victim</b> from the linked-list
* logfiles (it is probably present, but it might not be due to thread
* racing issues). After this function is called, the caller shouldn't
@@ -835,13 +885,26 @@ delete_log(logfile_t *victim)
}
/** Helper: release system resources (but not memory) held by a single
- * logfile_t. */
+ * signal-safe logfile_t. If the log's resources can not be released in
+ * a signal handler, does nothing. */
static void
-close_log(logfile_t *victim)
+close_log_sigsafe(logfile_t *victim)
{
if (victim->needs_close && victim->fd >= 0) {
+ /* We can't do anything useful here if close() fails: we're shutting
+ * down logging, and the err module only does fatal errors. */
close(victim->fd);
victim->fd = -1;
+ }
+}
+
+/** Helper: release system resources (but not memory) held by a single
+ * logfile_t. */
+static void
+close_log(logfile_t *victim)
+{
+ if (victim->needs_close) {
+ close_log_sigsafe(victim);
} else if (victim->is_syslog) {
#ifdef HAVE_SYSLOG_H
if (--syslog_count == 0) {