]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
log: when writing a log message to a TTY always end line in CRNL 30183/head
authorLennart Poettering <lennart@poettering.net>
Fri, 24 Nov 2023 09:50:47 +0000 (10:50 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 24 Nov 2023 10:09:24 +0000 (11:09 +0100)
This should make sure our log lines look nice even if the tty we are
connected to is in raw mode. Normally, it's the TTY's job to turn an NL
we output into a CRNL and interpret it accordingly. However, if the tty
is in "raw" mode it won't do that. Specifically, this is controlled by
the ONLCR flag on the TTY. A TTY might be in raw mode if our "ptyfwd"
logic is used for example, where a 2nd tty is bi-directionally connected
to the primary tty, and duplicate processing is not desired.

Hence, let's just write out the CR on our own. This will make sure that
whenever we output something subsequent output always continues on the
beginning of the next line again, regardless the mode the TTY is in. Of
course, if the TTY is *not* in raw mode, then the extra CR we now
generate is redundant, but it shouldn't hurt either, as it just moves
the cursor to the front of the line even though already is just there.

We only to that if we actually talk to a TTY though, since we don't want
the extra CRs if we are redirected to a pipe or file or so. We are not
on Windows after all.

Fixes: #30155
src/basic/log.c

index 0d78ecfd241cd13fc306447519c902193c219a35..1470611a75d00eed22896a1aa8921b087ca7d2a3 100644 (file)
@@ -53,6 +53,7 @@ static int log_facility = LOG_DAEMON;
 static bool ratelimit_kmsg = true;
 
 static int console_fd = STDERR_FILENO;
+static int console_fd_is_tty = -1; /* tri-state: -1 means don't know */
 static int syslog_fd = -EBADF;
 static int kmsg_fd = -EBADF;
 static int journal_fd = -EBADF;
@@ -108,12 +109,14 @@ bool _log_message_dummy = false; /* Always false */
 static void log_close_console(void) {
         /* See comment in log_close_journal() */
         (void) safe_close_above_stdio(TAKE_FD(console_fd));
+        console_fd_is_tty = -1;
 }
 
 static int log_open_console(void) {
 
         if (!always_reopen_console) {
                 console_fd = STDERR_FILENO;
+                console_fd_is_tty = -1;
                 return 0;
         }
 
@@ -125,6 +128,7 @@ static int log_open_console(void) {
                         return fd;
 
                 console_fd = fd_move_above_stdio(fd);
+                console_fd_is_tty = true;
         }
 
         return 0;
@@ -381,6 +385,7 @@ void log_forget_fds(void) {
         /* Do not call from library code. */
 
         console_fd = kmsg_fd = syslog_fd = journal_fd = -EBADF;
+        console_fd_is_tty = -1;
 }
 
 void log_set_max_level(int level) {
@@ -404,6 +409,16 @@ void log_set_facility(int facility) {
         log_facility = facility;
 }
 
+static bool check_console_fd_is_tty(void) {
+        if (console_fd < 0)
+                return false;
+
+        if (console_fd_is_tty < 0)
+                console_fd_is_tty = isatty(console_fd) > 0;
+
+        return console_fd_is_tty;
+}
+
 static int write_to_console(
                 int level,
                 int error,
@@ -462,7 +477,12 @@ static int write_to_console(
         iovec[n++] = IOVEC_MAKE_STRING(buffer);
         if (off)
                 iovec[n++] = IOVEC_MAKE_STRING(off);
-        iovec[n++] = IOVEC_MAKE_STRING("\n");
+
+        /* When writing to a TTY we output an extra '\r' (i.e. CR) first, to generate CRNL rather than just
+         * NL. This is a robustness thing in case the TTY is currently in raw mode (specifically: has the
+         * ONLCR flag off). We want that subsequent output definitely starts at the beginning of the line
+         * again, after all. If the TTY is not in raw mode the extra CR should not hurt. */
+        iovec[n++] = IOVEC_MAKE_STRING(check_console_fd_is_tty() ? "\r\n" : "\n");
 
         if (writev(console_fd, iovec, n) < 0) {