From: Nandakumar Raghavan Date: Mon, 16 Mar 2026 10:42:08 +0000 (+0000) Subject: ansi-color: fix SYSTEMD_COLORS=true regression when output is piped X-Git-Tag: v261-rc1~818 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a4aae324784565a838983602ca527df89dfc9316;p=thirdparty%2Fsystemd.git ansi-color: fix SYSTEMD_COLORS=true regression when output is piped The SYSTEMD_COLORS=true/1/yes no longer forced colors when stdout was not a TTY (e.g. piped), because the COLOR_TRUE bypass of the terminal_is_dumb() check was accidentally dropped. Restore the old behavior by guarding the TTY check with `m != COLOR_TRUE`, so an explicit boolean "true" value continues to unconditionally force color output regardless of whether stdout is a TTY or whether $NO_COLOR is set. --- diff --git a/src/basic/ansi-color.c b/src/basic/ansi-color.c index e5c78c93458..36cdca727c9 100644 --- a/src/basic/ansi-color.c +++ b/src/basic/ansi-color.c @@ -58,16 +58,20 @@ static ColorMode get_color_mode_impl(void) { if (m >= 0 && m < _COLOR_MODE_FIXED_MAX) return m; - /* Next, check for the presence of $NO_COLOR; value is ignored. */ - if (m != COLOR_TRUE && getenv("NO_COLOR")) - return COLOR_OFF; - - /* If the above didn't work, we turn colors off unless we are on a TTY. And if we are on a TTY we - * turn it off if $TERM is set to "dumb". There's one special tweak though: if we are PID 1 then we - * do not check whether we are connected to a TTY, because we don't keep /dev/console open - * continuously due to fear of SAK, and hence things are a bit weird. */ - if (getpid_cached() == 1 ? getenv_terminal_is_dumb() : terminal_is_dumb()) - return COLOR_OFF; + /* If SYSTEMD_COLORS=true was set explicitly, skip the environment checks below — the user + * explicitly requested colors, so honor it even when stdout is piped or $NO_COLOR is set. */ + if (m != COLOR_TRUE) { + /* Check for the presence of $NO_COLOR; value is ignored. */ + if (getenv("NO_COLOR")) + return COLOR_OFF; + + /* Turn colors off unless we are on a TTY. And if we are on a TTY we turn it off if $TERM + * is set to "dumb". There's one special tweak though: if we are PID 1 then we do not check + * whether we are connected to a TTY, because we don't keep /dev/console open continuously + * due to fear of SAK, and hence things are a bit weird. */ + if (getpid_cached() == 1 ? getenv_terminal_is_dumb() : terminal_is_dumb()) + return COLOR_OFF; + } /* We failed to figure out any reason to *disable* colors. Let's see how many colors we shall use. */ if (m == COLOR_AUTO_16) diff --git a/src/test/test-terminal-util.c b/src/test/test-terminal-util.c index 4e2b751ad26..efaed72b10b 100644 --- a/src/test/test-terminal-util.c +++ b/src/test/test-terminal-util.c @@ -338,13 +338,17 @@ TEST(get_color_mode) { test_get_color_mode_with_env("SYSTEMD_COLORS", "auto-256", terminal_is_dumb() ? COLOR_OFF : COLOR_256); test_get_color_mode_with_env("SYSTEMD_COLORS", "auto-24bit", terminal_is_dumb() ? COLOR_OFF : COLOR_24BIT); ASSERT_OK_ERRNO(setenv("COLORTERM", "truecolor", true)); - test_get_color_mode_with_env("SYSTEMD_COLORS", "1", terminal_is_dumb() ? COLOR_OFF : COLOR_24BIT); - test_get_color_mode_with_env("SYSTEMD_COLORS", "yes", terminal_is_dumb() ? COLOR_OFF : COLOR_24BIT); + /* SYSTEMD_COLORS=1/yes/true all map to COLOR_TRUE and must force colors on + * even when stdout is not a TTY (piped). With COLORTERM=truecolor, we get 24bit. */ + test_get_color_mode_with_env("SYSTEMD_COLORS", "1", COLOR_24BIT); + test_get_color_mode_with_env("SYSTEMD_COLORS", "yes", COLOR_24BIT); ASSERT_OK_ERRNO(unsetenv("COLORTERM")); - test_get_color_mode_with_env("SYSTEMD_COLORS", "true", terminal_is_dumb() ? COLOR_OFF : COLOR_256); + /* Without COLORTERM, COLOR_TRUE still bypasses the TTY check but autodetects depth. */ + test_get_color_mode_with_env("SYSTEMD_COLORS", "true", COLOR_256); ASSERT_OK_ERRNO(setenv("NO_COLOR", "1", true)); - test_get_color_mode_with_env("SYSTEMD_COLORS", "true", terminal_is_dumb() ? COLOR_OFF : COLOR_256); + /* COLOR_TRUE also bypasses NO_COLOR. */ + test_get_color_mode_with_env("SYSTEMD_COLORS", "true", COLOR_256); test_get_color_mode_with_env("SYSTEMD_COLORS", "auto-16", COLOR_OFF); test_get_color_mode_with_env("SYSTEMD_COLORS", "auto-256", COLOR_OFF); test_get_color_mode_with_env("SYSTEMD_COLORS", "auto-24bit", COLOR_OFF);