From 2a16ffab1be5c4dc7bd0bba83f6b93997f955f69 Mon Sep 17 00:00:00 2001 From: Dan Helfman Date: Sun, 2 Mar 2025 10:32:57 -0800 Subject: [PATCH] When ctrl-C is pressed, ensure Borg actually exits (#1015). --- NEWS | 1 + borgmatic/signals.py | 3 +++ tests/unit/test_signals.py | 8 +++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index ac0e36b7..3f64c8d2 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ using an environment variable. * #1013: Send database passwords to MongoDB via anonymous pipe, which is more secure than using "--password" on the command-line. + * #1015: When ctrl-C is pressed, ensure Borg actually exits. * Add a "verify_tls" option to the Uptime Kuma monitoring hook for disabling TLS verification. 1.9.12 diff --git a/borgmatic/signals.py b/borgmatic/signals.py index 7ec31d91..40fa5295 100644 --- a/borgmatic/signals.py +++ b/borgmatic/signals.py @@ -24,6 +24,9 @@ def handle_signal(signal_number, frame): logger.critical('Exiting due to TERM signal') sys.exit(EXIT_CODE_FROM_SIGNAL + signal.SIGTERM) elif signal_number == signal.SIGINT: + # Borg doesn't always exit on a SIGINT, so give it a little encouragement. + os.killpg(os.getpgrp(), signal.SIGTERM) + raise KeyboardInterrupt() diff --git a/tests/unit/test_signals.py b/tests/unit/test_signals.py index 86bb759c..57ee14ab 100644 --- a/tests/unit/test_signals.py +++ b/tests/unit/test_signals.py @@ -26,7 +26,7 @@ def test_handle_signal_bails_on_recursion(): def test_handle_signal_exits_on_sigterm(): signal_number = module.signal.SIGTERM frame = flexmock(f_back=flexmock(f_code=flexmock(co_name='something'))) - flexmock(module.os).should_receive('getpgrp').and_return(flexmock) + flexmock(module.os).should_receive('getpgrp').and_return(flexmock()) flexmock(module.os).should_receive('killpg') flexmock(module.sys).should_receive('exit').with_args( module.EXIT_CODE_FROM_SIGNAL + signal_number @@ -38,8 +38,10 @@ def test_handle_signal_exits_on_sigterm(): def test_handle_signal_raises_on_sigint(): signal_number = module.signal.SIGINT frame = flexmock(f_back=flexmock(f_code=flexmock(co_name='something'))) - flexmock(module.os).should_receive('getpgrp').and_return(flexmock) - flexmock(module.os).should_receive('killpg') + process_group = flexmock() + flexmock(module.os).should_receive('getpgrp').and_return(process_group) + flexmock(module.os).should_receive('killpg').with_args(process_group, module.signal.SIGINT) + flexmock(module.os).should_receive('killpg').with_args(process_group, module.signal.SIGTERM) flexmock(module.sys).should_receive('exit').never() with pytest.raises(KeyboardInterrupt):