Explorar o código

Merge pull request #6944 from ThomasWaldmann/fix-ctrl-c-remote-repo-1.2

ctrl-c must not kill important subprocesses, fixes #6912
TW %!s(int64=2) %!d(string=hai) anos
pai
achega
ec389edc83
Modificáronse 3 ficheiros con 22 adicións e 7 borrados
  1. 3 3
      src/borg/archiver.py
  2. 15 2
      src/borg/helpers/process.py
  3. 4 2
      src/borg/remote.py

+ 3 - 3
src/borg/archiver.py

@@ -73,7 +73,7 @@ try:
     from .helpers import umount
     from .helpers import flags_root, flags_dir, flags_special_follow, flags_special
     from .helpers import msgpack
-    from .helpers import sig_int
+    from .helpers import sig_int, ignore_sigint
     from .helpers import iter_separated
     from .helpers import get_tar_filter
     from .nanorst import rst_to_terminal
@@ -527,7 +527,7 @@ class Archiver:
                 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
@@ -546,7 +546,7 @@ class Archiver:
                 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

+ 15 - 2
src/borg/helpers/process.py

@@ -228,6 +228,19 @@ class SigIntManager:
 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,
@@ -315,10 +328,10 @@ 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)
+                                             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)
+                                             log_prefix='filter-process: ', env=env, preexec_fn=ignore_sigint)
         if not proc:
             raise Error(f'filter {cmd}: process creation failed')
         stream = proc.stdout if inbound else proc.stdin

+ 4 - 2
src/borg/remote.py

@@ -26,7 +26,7 @@ from .helpers import replace_placeholders
 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
@@ -557,7 +557,9 @@ class RemoteRepository:
         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()