Răsfoiți Sursa

mount --show-rc: display main process rc, fixes #8308

when borg mount is used without -f/--foreground (so that the FUSE
borg process was started daemonized in the background), it did not
display the rc of the main process, even when --show-rc was used.

now it does display the rc of the main process.

note that this is rather a consistency fix than being super useful,
because the main "action" happens in the background daemon process,
not in the main process.
Thomas Waldmann 1 săptămână în urmă
părinte
comite
702de47197
4 a modificat fișierele cu 40 adăugiri și 19 ștergeri
  1. 3 16
      src/borg/archiver.py
  2. 2 2
      src/borg/fuse.py
  3. 28 0
      src/borg/helpers/__init__.py
  4. 7 1
      src/borg/helpers/process.py

+ 3 - 16
src/borg/archiver.py

@@ -1461,7 +1461,7 @@ class Archiver:
             operations = FuseOperations(key, repository, manifest, args, cached_repo)
             operations = FuseOperations(key, repository, manifest, args, cached_repo)
             logger.info("Mounting filesystem")
             logger.info("Mounting filesystem")
             try:
             try:
-                operations.mount(args.mountpoint, args.options, args.foreground)
+                operations.mount(args.mountpoint, args.options, args.foreground, args.show_rc)
             except RuntimeError:
             except RuntimeError:
                 # Relevant error message already printed to stderr by FUSE
                 # Relevant error message already printed to stderr by FUSE
                 raise RTError("FUSE mount failed")
                 raise RTError("FUSE mount failed")
@@ -5678,21 +5678,8 @@ def main():  # pragma: no cover
         if tb:
         if tb:
             logger.log(tb_log_level, tb)
             logger.log(tb_log_level, tb)
         if args.show_rc:
         if args.show_rc:
-            rc_logger = logging.getLogger('borg.output.show-rc')
-            exit_msg = 'terminating with %s status, rc %d'
-            try:
-                ec_class = classify_ec(exit_code)
-            except ValueError:
-                rc_logger.error(exit_msg % ('abnormal', exit_code or 666))
-            else:
-                if ec_class == "success":
-                    rc_logger.info(exit_msg % (ec_class, exit_code))
-                elif ec_class == "warning":
-                    rc_logger.warning(exit_msg % (ec_class, exit_code))
-                elif ec_class == "error":
-                    rc_logger.error(exit_msg % (ec_class, exit_code))
-                elif ec_class == "signal":
-                    rc_logger.error(exit_msg % (ec_class, exit_code))
+            from .helpers import do_show_rc
+            do_show_rc(exit_code)
         sys.exit(exit_code)
         sys.exit(exit_code)
 
 
 
 

+ 2 - 2
src/borg/fuse.py

@@ -484,7 +484,7 @@ class FuseOperations(llfuse.Operations, FuseBackend):
                      format_file_size(sum(len(chunk) for key, chunk in self.data_cache.items())))
                      format_file_size(sum(len(chunk) for key, chunk in self.data_cache.items())))
         self.decrypted_repository.log_instrumentation()
         self.decrypted_repository.log_instrumentation()
 
 
-    def mount(self, mountpoint, mount_options, foreground=False):
+    def mount(self, mountpoint, mount_options, foreground=False, show_rc=False):
         """Mount filesystem on *mountpoint* with *mount_options*."""
         """Mount filesystem on *mountpoint* with *mount_options*."""
 
 
         def pop_option(options, key, present, not_present, wanted_type, int_base=0):
         def pop_option(options, key, present, not_present, wanted_type, int_base=0):
@@ -556,7 +556,7 @@ class FuseOperations(llfuse.Operations, FuseBackend):
             if isinstance(self.repository_uncached, RemoteRepository):
             if isinstance(self.repository_uncached, RemoteRepository):
                 daemonize()
                 daemonize()
             else:
             else:
-                with daemonizing() as (old_id, new_id):
+                with daemonizing(show_rc=show_rc) as (old_id, new_id):
                     # local repo: the locking process' PID is changing, migrate it:
                     # local repo: the locking process' PID is changing, migrate it:
                     logger.debug('fuse: mount local repo, going to background: migrating lock.')
                     logger.debug('fuse: mount local repo, going to background: migrating lock.')
                     self.repository_uncached.migrate_lock(old_id, new_id)
                     self.repository_uncached.migrate_lock(old_id, new_id)

+ 28 - 0
src/borg/helpers/__init__.py

@@ -5,6 +5,7 @@ Code used to be in borg/helpers.py but was split into modules in this
 package, which are imported here for compatibility.
 package, which are imported here for compatibility.
 """
 """
 from contextlib import contextmanager
 from contextlib import contextmanager
+import logging
 
 
 from .checks import *  # NOQA
 from .checks import *  # NOQA
 from .datastruct import *  # NOQA
 from .datastruct import *  # NOQA
@@ -150,3 +151,30 @@ def get_reset_ec(ec=None):
     rc = get_ec(ec)
     rc = get_ec(ec)
     init_ec_warnings()
     init_ec_warnings()
     return rc
     return rc
+
+
+def do_show_rc(exit_code):
+    """Log the program return code using the dedicated 'borg.output.show-rc' logger.
+
+    Uses INFO/WARNING/ERROR levels depending on the classified exit code.
+
+    This helper is robust: it swallows any exceptions to avoid interfering with
+    program exit behavior. Callers do not need to guard it with try/except.
+    """
+    try:
+        exit_msg = 'terminating with %s status, rc %d'
+        rc_logger = logging.getLogger('borg.output.show-rc')
+        try:
+            ec_class = classify_ec(exit_code)
+        except ValueError:
+            rc_logger.error(exit_msg % ('abnormal', exit_code or 666))
+        else:
+            if ec_class == "success":
+                rc_logger.info(exit_msg % (ec_class, exit_code))
+            elif ec_class == "warning":
+                rc_logger.warning(exit_msg % (ec_class, exit_code))
+            elif ec_class in ("error", "signal"):
+                rc_logger.error(exit_msg % (ec_class, exit_code))
+    except Exception:
+        # Never let logging issues interfere with exit behaviour
+        pass

+ 7 - 1
src/borg/helpers/process.py

@@ -62,7 +62,7 @@ def daemonize():
 
 
 
 
 @contextlib.contextmanager
 @contextlib.contextmanager
-def daemonizing(*, timeout=5):
+def daemonizing(*, timeout=5, show_rc=False):
     """Like daemonize(), but as context manager.
     """Like daemonize(), but as context manager.
 
 
     The with-body is executed in the background process,
     The with-body is executed in the background process,
@@ -107,6 +107,12 @@ def daemonizing(*, timeout=5):
                     logger.warning('Daemonizing: Background process did not respond (timeout). Is it alive?')
                     logger.warning('Daemonizing: Background process did not respond (timeout). Is it alive?')
                     exit_code = EXIT_WARNING
                     exit_code = EXIT_WARNING
                 finally:
                 finally:
+                    # Before terminating the foreground process, honor --show-rc by logging the rc here as well.
+                    # This is mostly a consistency fix and not very useful considering that the main action
+                    # happens in the daemon process.
+                    if show_rc:
+                        from ..helpers import do_show_rc
+                        do_show_rc(exit_code)
                     # Don't call with-body, but die immediately!
                     # Don't call with-body, but die immediately!
                     # return would be sufficient, but we want to pass the exit code.
                     # return would be sufficient, but we want to pass the exit code.
                     raise _ExitCodeException(exit_code)
                     raise _ExitCodeException(exit_code)