From: Lennart Poettering Date: Fri, 24 Nov 2023 09:50:47 +0000 (+0100) Subject: log: when writing a log message to a TTY always end line in CRNL X-Git-Tag: v256-rc1~1580^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d19ddf91fdaf2661a6fed2908a64f6ae9cd54c50;p=thirdparty%2Fsystemd.git log: when writing a log message to a TTY always end line in CRNL 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 --- diff --git a/src/basic/log.c b/src/basic/log.c index 0d78ecfd241..1470611a75d 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -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) {