chiark / gitweb /
log: when we log to /dev/console and got disconnected (maybe due to vhangup) reconnect
[elogind.git] / src / shared / log.c
index 27317f7ed3ce13c4811d8ad53fa311f6e7b9e785..b5b82f61c18774feda281b201e4e6cef2944be7f 100644 (file)
@@ -115,16 +115,20 @@ void log_close_syslog(void) {
 
 static int create_log_socket(int type) {
         int fd;
+        struct timeval tv;
 
-        /* All output to the syslog/journal fds we do asynchronously,
-         * and if the buffers are full we just drop the messages */
-
-        fd = socket(AF_UNIX, type|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+        fd = socket(AF_UNIX, type|SOCK_CLOEXEC, 0);
         if (fd < 0)
                 return -errno;
 
         fd_inc_sndbuf(fd, SNDBUF_SIZE);
 
+        /* We need a blocking fd here since we'd otherwise lose
+        messages way too early. However, let's not hang forever in the
+        unlikely case of a deadlock. */
+        timeval_store(&tv, 1*USEC_PER_MINUTE);
+        setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
+
         return fd;
 }
 
@@ -268,8 +272,6 @@ int log_open(void) {
         log_close_journal();
         log_close_syslog();
 
-        /* Get the real /dev/console if we are PID=1, hence reopen */
-        log_close_console();
         return log_open_console();
 }
 
@@ -333,8 +335,25 @@ static int write_to_console(
                 IOVEC_SET_STRING(iovec[n++], ANSI_HIGHLIGHT_OFF);
         IOVEC_SET_STRING(iovec[n++], "\n");
 
-        if (writev(console_fd, iovec, n) < 0)
-                return -errno;
+        if (writev(console_fd, iovec, n) < 0) {
+
+                if (errno == EIO && getpid() == 1) {
+
+                        /* If somebody tried to kick us from our
+                         * console tty (via vhangup() or suchlike),
+                         * try to reconnect */
+
+                        log_close_console();
+                        log_open_console();
+
+                        if (console_fd < 0)
+                                return 0;
+
+                        if (writev(console_fd, iovec, n) < 0)
+                                return -errno;
+                } else
+                        return -errno;
+        }
 
         return 1;
 }
@@ -683,25 +702,34 @@ int log_meta_object(
 
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
-_noreturn_ static void log_assert(const char *text, const char *file, int line, const char *func, const char *format) {
+static void log_assert(int level, const char *text, const char *file, int line, const char *func, const char *format) {
         static char buffer[LINE_MAX];
 
+        if (_likely_(LOG_PRI(level) > log_max_level))
+                return;
+
         snprintf(buffer, sizeof(buffer), format, text, file, line, func);
 
         char_array_0(buffer);
         log_abort_msg = buffer;
 
-        log_dispatch(LOG_CRIT, file, line, func, NULL, NULL, buffer);
-        abort();
+        log_dispatch(level, file, line, func, NULL, NULL, buffer);
 }
 #pragma GCC diagnostic pop
 
-_noreturn_ void log_assert_failed(const char *text, const char *file, int line, const char *func) {
-        log_assert(text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
+noreturn void log_assert_failed(const char *text, const char *file, int line, const char *func) {
+        log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting.");
+        abort();
 }
 
-_noreturn_ void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
-        log_assert(text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
+noreturn void log_assert_failed_unreachable(const char *text, const char *file, int line, const char *func) {
+        log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting.");
+        abort();
+}
+
+void log_assert_failed_return(const char *text, const char *file, int line, const char *func) {
+        PROTECT_ERRNO;
+        log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring.");
 }
 
 int log_oom_internal(const char *file, int line, const char *func) {