1
0
Fork 0
mirror of https://github.com/borgbackup/borg.git synced 2024-12-25 01:06:50 +00:00

Merge pull request #6949 from ThomasWaldmann/fix-ctrl-c-remote-repo-master

ctrl-c must not kill important subprocesses, fixes #6912
This commit is contained in:
TW 2022-08-07 18:35:45 +02:00 committed by GitHub
commit 7b2be94262
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 8 deletions

View file

@ -26,7 +26,7 @@
from ..helpers import log_multi
from ..helpers import basic_json_data, json_print
from ..helpers import flags_root, flags_dir, flags_special_follow, flags_special
from ..helpers import sig_int
from ..helpers import sig_int, ignore_sigint
from ..helpers import iter_separated
from ..patterns import PatternMatcher
from ..platform import get_flags
@ -68,7 +68,7 @@ def create_inner(archive, cache, fso):
if not dry_run:
try:
try:
proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE)
proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE, preexec_fn=ignore_sigint)
except (FileNotFoundError, PermissionError) as e:
self.print_error("Failed to execute command: %s", e)
return self.exit_code
@ -89,7 +89,7 @@ def create_inner(archive, cache, fso):
paths_sep = eval_escapes(args.paths_delimiter) if args.paths_delimiter is not None else "\n"
if args.paths_from_command:
try:
proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE)
proc = subprocess.Popen(args.paths, stdout=subprocess.PIPE, preexec_fn=ignore_sigint)
except (FileNotFoundError, PermissionError) as e:
self.print_error("Failed to execute command: %s", e)
return self.exit_code

View file

@ -31,7 +31,8 @@
from .parseformat import BaseFormatter, ArchiveFormatter, ItemFormatter, file_status
from .parseformat import swidth_slice, ellipsis_truncate
from .parseformat import BorgJsonEncoder, basic_json_data, json_print, json_dump, prepare_dump_dict
from .process import daemonize, daemonizing, signal_handler, raising_signal_handler, sig_int, SigHup, SigTerm
from .process import daemonize, daemonizing
from .process import signal_handler, raising_signal_handler, sig_int, ignore_sigint, SigHup, SigTerm
from .process import popen_with_error_handling, is_terminal, prepare_subprocess_env, create_filter_process
from .progress import ProgressIndicatorPercent, ProgressIndicatorEndless, ProgressIndicatorMessage
from .time import parse_timestamp, timestamp, safe_timestamp, safe_s, safe_ns, MAX_S, SUPPORT_32BIT_PLATFORMS

View file

@ -236,6 +236,19 @@ def __exit__(self, exception_type, exception_value, traceback):
sig_int = SigIntManager()
def ignore_sigint():
"""
Ignore SIGINT, see also issue #6912.
Ctrl-C will send a SIGINT to both the main process (borg) and subprocesses
(e.g. ssh for remote ssh:// repos), but often we do not want the subprocess
getting killed (e.g. because it is still needed to cleanly shut down borg).
To avoid that: Popen(..., preexec_fn=ignore_sigint)
"""
signal.signal(signal.SIGINT, signal.SIG_IGN)
def popen_with_error_handling(cmd_line: str, log_prefix="", **kwargs):
"""
Handle typical errors raised by subprocess.Popen. Return None if an error occurred,
@ -323,11 +336,21 @@ def create_filter_process(cmd, stream, stream_close, inbound=True):
# for us to do something while we block on the process for something different.
if inbound:
proc = popen_with_error_handling(
cmd, stdout=subprocess.PIPE, stdin=filter_stream, log_prefix="filter-process: ", env=env
cmd,
stdout=subprocess.PIPE,
stdin=filter_stream,
log_prefix="filter-process: ",
env=env,
preexec_fn=ignore_sigint,
)
else:
proc = popen_with_error_handling(
cmd, stdin=subprocess.PIPE, stdout=filter_stream, log_prefix="filter-process: ", env=env
cmd,
stdin=subprocess.PIPE,
stdout=filter_stream,
log_prefix="filter-process: ",
env=env,
preexec_fn=ignore_sigint,
)
if not proc:
raise Error(f"filter {cmd}: process creation failed")

View file

@ -26,7 +26,7 @@
from .helpers import sysinfo
from .helpers import format_file_size
from .helpers import safe_unlink
from .helpers import prepare_subprocess_env
from .helpers import prepare_subprocess_env, ignore_sigint
from .logger import create_logger, setup_logging
from .helpers import msgpack
from .repository import Repository
@ -582,7 +582,9 @@ def __init__(
if not testing:
borg_cmd = self.ssh_cmd(location) + borg_cmd
logger.debug("SSH command line: %s", borg_cmd)
self.p = Popen(borg_cmd, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env)
# we do not want the ssh getting killed by Ctrl-C/SIGINT because it is needed for clean shutdown of borg.
# borg's SIGINT handler tries to write a checkpoint and requires the remote repo connection.
self.p = Popen(borg_cmd, bufsize=0, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env, preexec_fn=ignore_sigint)
self.stdin_fd = self.p.stdin.fileno()
self.stdout_fd = self.p.stdout.fileno()
self.stderr_fd = self.p.stderr.fileno()