aboutsummaryrefslogtreecommitdiff
path: root/src/common/log.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common/log.c')
-rw-r--r--src/common/log.c125
1 files changed, 109 insertions, 16 deletions
diff --git a/src/common/log.c b/src/common/log.c
index 303fba93a..3ce4df190 100644
--- a/src/common/log.c
+++ b/src/common/log.c
@@ -443,6 +443,115 @@ tor_log(int severity, log_domain_mask_t domain, const char *format, ...)
va_end(ap);
}
+/** Maximum number of fds that will get notifications if we crash */
+#define MAX_SIGSAFE_FDS 8
+/** Array of fds to log crash-style warnings to. */
+static int sigsafe_log_fds[MAX_SIGSAFE_FDS] = { STDERR_FILENO };
+/** The number of elements used in sigsafe_log_fds */
+static int n_sigsafe_log_fds = 1;
+
+/** Write <b>s</b> to each element of sigsafe_log_fds. Return 0 on success, -1
+ * on failure. */
+static int
+tor_log_err_sigsafe_write(const char *s)
+{
+ int i;
+ ssize_t r;
+ size_t len = strlen(s);
+ int err = 0;
+ for (i=0; i < n_sigsafe_log_fds; ++i) {
+ r = write(sigsafe_log_fds[i], s, len);
+ err += (r != (ssize_t)len);
+ }
+ return err ? -1 : 0;
+}
+
+/** Given a list of string arguments ending with a NULL, writes them
+ * to our logs and to stderr (if possible). This function is safe to call
+ * from within a signal handler. */
+void
+tor_log_err_sigsafe(const char *m, ...)
+{
+ va_list ap;
+ const char *x;
+ char timebuf[32];
+ time_t now = time(NULL);
+
+ if (!m)
+ return;
+ if (log_time_granularity >= 2000) {
+ int g = log_time_granularity / 1000;
+ now -= now % g;
+ }
+ timebuf[0] = '\0';
+ format_dec_number_sigsafe(now, timebuf, sizeof(timebuf));
+ tor_log_err_sigsafe_write("\n=========================================="
+ "================== T=");
+ tor_log_err_sigsafe_write(timebuf);
+ tor_log_err_sigsafe_write("\n");
+ tor_log_err_sigsafe_write(m);
+ va_start(ap, m);
+ while ((x = va_arg(ap, const char*))) {
+ tor_log_err_sigsafe_write(x);
+ }
+ va_end(ap);
+}
+
+/** Set *<b>out</b> to a pointer to an array of the fds to log errors to from
+ * inside a signal handler. Return the number of elements in the array. */
+int
+tor_log_get_sigsafe_err_fds(const int **out)
+{
+ *out = sigsafe_log_fds;
+ return n_sigsafe_log_fds;
+}
+
+/** Helper function; return true iff the <b>n</b>-element array <b>array</b>
+ * contains <b>item</b>. */
+static int
+int_array_contains(const int *array, int n, int item)
+{
+ int j;
+ for (j = 0; j < n; ++j) {
+ if (array[j] == item)
+ return 1;
+ }
+ return 0;
+}
+
+/** Function to call whenever the list of logs changes to get ready to log
+ * from signal handlers. */
+void
+tor_log_update_sigsafe_err_fds(void)
+{
+ const logfile_t *lf;
+
+ LOCK_LOGS();
+ /* Always try for stderr. This is safe because when we daemonize, we dup2
+ * /dev/null to stderr, */
+ sigsafe_log_fds[0] = STDERR_FILENO;
+ n_sigsafe_log_fds = 1;
+
+ for (lf = logfiles; lf; lf = lf->next) {
+ /* Don't try callback to the control port, or syslogs: We can't
+ * do them from a signal handler. Don't try stdout: we always do stderr.
+ */
+ if (lf->is_temporary || lf->is_syslog ||
+ lf->callback || lf->seems_dead || lf->fd < 0)
+ continue;
+ if (lf->severities->masks[SEVERITY_MASK_IDX(LOG_ERR)] &
+ (LD_BUG|LD_GENERAL)) {
+ /* Avoid duplicates */
+ if (int_array_contains(sigsafe_log_fds, n_sigsafe_log_fds, lf->fd))
+ continue;
+ sigsafe_log_fds[n_sigsafe_log_fds++] = lf->fd;
+ if (n_sigsafe_log_fds == MAX_SIGSAFE_FDS)
+ break;
+ }
+ }
+ UNLOCK_LOGS();
+}
+
/** Output a message to the log, prefixed with a function name <b>fn</b>. */
#ifdef __GNUC__
/** GCC-based implementation of the log_fn backend, used when we have
@@ -1142,22 +1251,6 @@ get_min_log_level(void)
return min;
}
-/** Return the fd of a file log that is receiving ERR messages, or -1 if
- * no such log exists. */
-int
-get_err_logging_fd(void)
-{
- const logfile_t *lf;
- for (lf = logfiles; lf; lf = lf->next) {
- if (lf->is_temporary || lf->is_syslog || !lf->filename ||
- lf->callback || lf->seems_dead || lf->fd < 0)
- continue;
- if (lf->severities->masks[LOG_ERR] & LD_GENERAL)
- return lf->fd;
- }
- return -1;
-}
-
/** Switch all logs to output at most verbose level. */
void
switch_logs_debug(void)