From nobody Tue Apr 7 18:46:39 2026 Received: from mail-pf1-f175.google.com (mail-pf1-f175.google.com [209.85.210.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 98B152A1CF for ; Fri, 27 Feb 2026 12:31:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772195504; cv=none; b=AX2D/Av88yq8tQPl5wvRbjOdVi6iQK+e5K5/F/2ZYMp77NwbxHAiDIQqPEXYpttY/CNwSIJUkwrSEaq99UDLZkqxh6jILU6BZyJVvKVP1SuiONFR/X0Ox+ZZTa/+yQcreiAwhCEd1UR+Vlsdv9S/LFOud43UbcGAVcJCBQT29SI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772195504; c=relaxed/simple; bh=v2/57WwF8w7iACHfTCkO5W9+hM3Krg3WvgtT0li001I=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=VHqKvWwrSNA4WRPhmKHv3bzO2Uzy0V8AXrjwVwFS6+kmrCRqAmZx3X2pHnM6YXAwpf1jHzlFp+9NMG2T6svxxb1PK6DEu0qKWwgU5CvUJeQ5EC+20rKCj9BRFQ5ZSe3a+LTPQ8Ms6i89w8DQCnRZY+X1GJXeHJAGqN7kWoaEq70= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=G5SLup0z; arc=none smtp.client-ip=209.85.210.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="G5SLup0z" Received: by mail-pf1-f175.google.com with SMTP id d2e1a72fcca58-8249fc726e9so1190098b3a.2 for ; Fri, 27 Feb 2026 04:31:43 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772195503; x=1772800303; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=ajshf8l6anZvHOKZ2eAGK/RXqDyQYxeDuW8fo/WYnWI=; b=G5SLup0zCW7uYyKPE3yGlJpcOgJzAEZI4Xcx2+Bvy8Ob4cu8Xyb1uqhP3MVe5SAdYZ yPppYIMADWFC/FqgUsdB2hj1vQreNl19YZT23y9fIpVHM4Aa/qtSqxOQDrDKRFYmjoql ugG9RHf9UTcYPQio7Zx1BJg3sMTPyAQjRperUY1FxPnwRFBUTD9DnRX6E6LVuc4iWRP5 2eEFzzNi0FAebPRpFwRSLB+tfrEpU4AWFbKCT4lJzvON5hRdpjH8/J3Ow7vUIXHpSqqW zHLdJatZl5JJ5K3O1r4XLkRTxjJYx5QpWKAlIfzfnjlbLMNMToPTr1cmtOpiUKT9xvbM VQTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772195503; x=1772800303; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=ajshf8l6anZvHOKZ2eAGK/RXqDyQYxeDuW8fo/WYnWI=; b=NtWyc4cafcuGJJUpLKpGXc1Bdn2N+sHcrsbHPGGOZ3T9zpRQgGqSFKMqqnRz7cPzbK hCxb3gq463lNXv3pC8wDcNibUWBMckx+w4JKdew72kKw8Zu2DyZSkN7xVFH0d6VIqWSY Hz2c2AqHsyH+XhCY1stwcloh5vboGW5C/p1zIHiUzwHyZtWQru9O+KeoWSA0Z1XFFma9 RMuBHidVy7yFiWO7Cn8TIdXdqfQx7RUv8PKfmn5IN6MD4vO5nt+oG4jWVHpNKiLKQ5B7 GfeltFnORi+NeLMZNszeAQXFrNLsOmJWson4NlOiQGT+uoT3t10CvcTgthYqo2F8LiOi qHFQ== X-Forwarded-Encrypted: i=1; AJvYcCWyYhv5SsgtjC4r9PPhL8eUnWuml7sI4eTkjfCQizk4tHiwcmg07CdOWvK9LC/LnJ6iEu/3hWaoEBb0wz8=@vger.kernel.org X-Gm-Message-State: AOJu0YxBgcKndn6Xw3rtlGkaoIxRO8G76MwVbQDuK3vN0B2PTTj/RnUK HMrpBcC1jGTMGjDtpXrSbfjznW6Xu32VVi+bFaqCxn/NiAAaAcYVIrD9W+5HhcfcrAQ= X-Gm-Gg: ATEYQzwphc1OO6d5rOH/938/BZqq2nVuqCGx/Rcjglc458yjprAln6mHzgvS495hCXr YKbTe98SB6F8QcIPG1nyAWEDme1f32lGe0zmhrgd7OzzkGbigizcRoR+fwBj79pK0vCzS3stbBK sagFn0EujhTyomkjqteoYX4DVVO6k2+R8kf7FAWeUOLk3LekWO6cfN9Yu2RDdPn5X7C9PhGcH2m mAjksUIjTM6nD1ruMYjMdXOreddWZAoNueJW71F/lcFRBei8BM0aJGyPv3i4qWi+MUNF6Noe19R 2i4HxSpsGnDizrDYdxErE5aPXa/ZJ5IpMIp1VmbLuv5BWEDA3BVx8QMNGuvSZA/sXvWp1X2wq1P bJX3NTHyaQlsPmEuqGIdxVFM60w4Svxc2CbvrMLB2WUwleTzxe/6M7fbqvuwZJ0QR6lhsH81q3b RDKEyjXIRBGMTIk8StGNAFBmb8Y3igpQmMwiQ5S94nnkx8hHhuyFjZeYBgi+4Bqw== X-Received: by 2002:a05:6a20:938b:b0:394:6646:d3eb with SMTP id adf61e73a8af0-395c3b3abf9mr2842434637.64.1772195502633; Fri, 27 Feb 2026 04:31:42 -0800 (PST) Received: from mac ([49.244.49.25]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3593dcad63esm6380432a91.2.2026.02.27.04.31.39 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Fri, 27 Feb 2026 04:31:42 -0800 (PST) From: Shuvam Pandey To: brendan.higgins@linux.dev, davidgow@google.com Cc: raemoar63@gmail.com, linux-kselftest@vger.kernel.org, kunit-dev@googlegroups.com, linux-kernel@vger.kernel.org, Shuvam Pandey Subject: [PATCH] kunit: tool: skip stty when stdin is not a tty Date: Fri, 27 Feb 2026 18:16:36 +0545 Message-ID: <20260227123136.91086-1-shuvampandey1@gmail.com> X-Mailer: git-send-email 2.50.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" run_kernel() cleanup and signal_handler() invoke stty unconditionally. When stdin is not a tty (for example in CI or unit tests), this writes noise to stderr. Call stty only when stdin is a tty. Add regression tests for these paths: - run_kernel() with non-tty stdin - signal_handler() with non-tty stdin - signal_handler() with tty stdin Signed-off-by: Shuvam Pandey Reviewed-by: David Gow --- tools/testing/kunit/kunit_kernel.py | 10 ++++-- tools/testing/kunit/kunit_tool_test.py | 42 ++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/tools/testing/kunit/kunit_kernel.py b/tools/testing/kunit/kuni= t_kernel.py index 260d8d9aa1db..6f49b184a6fb 100644 --- a/tools/testing/kunit/kunit_kernel.py +++ b/tools/testing/kunit/kunit_kernel.py @@ -345,6 +345,12 @@ class LinuxSourceTree: return False return self.validate_config(build_dir) =20 + def _restore_terminal_if_tty(self) -> None: + # stty requires a controlling terminal; skip headless runs. + if sys.stdin is None or not sys.stdin.isatty(): + return + subprocess.call(['stty', 'sane']) + def run_kernel(self, args: Optional[List[str]]=3DNone, build_dir: str=3D'= ', filter_glob: str=3D'', filter: str=3D'', filter_action: Optional[str]=3D= None, timeout: Optional[int]=3DNone) -> Iterator[str]: if not args: args =3D [] @@ -384,8 +390,8 @@ class LinuxSourceTree: process.stdout.close() =20 waiter.join() - subprocess.call(['stty', 'sane']) + self._restore_terminal_if_tty() =20 def signal_handler(self, unused_sig: int, unused_frame: Optional[FrameTyp= e]) -> None: logging.error('Build interruption occurred. Cleaning console.') - subprocess.call(['stty', 'sane']) + self._restore_terminal_if_tty() diff --git a/tools/testing/kunit/kunit_tool_test.py b/tools/testing/kunit/k= unit_tool_test.py index b67408147c1f..201d5245a9f4 100755 --- a/tools/testing/kunit/kunit_tool_test.py +++ b/tools/testing/kunit/kunit_tool_test.py @@ -503,6 +503,48 @@ class LinuxSourceTreeTest(unittest.TestCase): with open(kunit_kernel.get_outfile_path(build_dir), 'rt') as outfile: self.assertEqual(outfile.read(), 'hi\nbye\n', msg=3D'Missing some outp= ut') =20 + def test_run_kernel_skips_terminal_reset_without_tty(self): + def fake_start(unused_args, unused_build_dir): + return subprocess.Popen(['printf', 'KTAP version 1\n'], + text=3DTrue, stdout=3Dsubprocess.PIPE) + + non_tty_stdin =3D mock.Mock() + non_tty_stdin.isatty.return_value =3D False + + with tempfile.TemporaryDirectory('') as build_dir: + tree =3D kunit_kernel.LinuxSourceTree(build_dir, kunitconfig_paths=3D[o= s.devnull]) + with mock.patch.object(tree._ops, 'start', side_effect=3Dfake_start), \ + mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call: + for _ in tree.run_kernel(build_dir=3Dbuild_dir): + pass + + mock_call.assert_not_called() + + def test_signal_handler_skips_terminal_reset_without_tty(self): + non_tty_stdin =3D mock.Mock() + non_tty_stdin.isatty.return_value =3D False + tree =3D kunit_kernel.LinuxSourceTree('', kunitconfig_paths=3D[os.devnul= l]) + + with mock.patch.object(kunit_kernel.sys, 'stdin', non_tty_stdin), \ + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ + mock.patch.object(kunit_kernel.logging, 'error') as mock_error: + tree.signal_handler(signal.SIGINT, None) + mock_error.assert_called_once() + mock_call.assert_not_called() + + def test_signal_handler_resets_terminal_with_tty(self): + tty_stdin =3D mock.Mock() + tty_stdin.isatty.return_value =3D True + tree =3D kunit_kernel.LinuxSourceTree('', kunitconfig_paths=3D[os.devnul= l]) + + with mock.patch.object(kunit_kernel.sys, 'stdin', tty_stdin), \ + mock.patch.object(kunit_kernel.subprocess, 'call') as mock_call, \ + mock.patch.object(kunit_kernel.logging, 'error') as mock_error: + tree.signal_handler(signal.SIGINT, None) + mock_error.assert_called_once() + mock_call.assert_called_once_with(['stty', 'sane']) + def test_build_reconfig_no_config(self): with tempfile.TemporaryDirectory('') as build_dir: with open(kunit_kernel.get_kunitconfig_path(build_dir), 'w') as f: base-commit: a75cb869a8ccc88b0bc7a44e1597d9c7995c56e5 --=20 2.50.0