/usr/share/pyshared/rdiff_backup/robust.py is in rdiff-backup 1.2.8-7.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | # Copyright 2002 Ben Escoto
#
# This file is part of rdiff-backup.
#
# rdiff-backup is free software; you can redistribute it and/or modify
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#
# rdiff-backup is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with rdiff-backup; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA
"""Catch various exceptions given system call"""
import errno, signal, exceptions, zlib
import librsync, C, static, rpath, Globals, log, statistics, connection
def check_common_error(error_handler, function, args = []):
"""Apply function to args, if error, run error_handler on exception
This uses the catch_error predicate below to only catch
certain exceptions which seems innocent enough.
"""
try: return function(*args)
except (Exception, KeyboardInterrupt, SystemExit), exc:
TracebackArchive.add([function] + list(args))
if catch_error(exc):
log.Log.exception()
conn = Globals.backup_writer
if conn is not None: conn.statistics.record_error()
if error_handler: return error_handler(exc, *args)
else: return None
if is_routine_fatal(exc): log.Log.exception(1, 6)
else: log.Log.exception(1, 2)
raise
def catch_error(exc):
"""Return true if exception exc should be caught"""
for exception_class in (rpath.SkipFileException, rpath.RPathException,
librsync.librsyncError, C.UnknownFileTypeError,
zlib.error):
if isinstance(exc, exception_class): return 1
if (isinstance(exc, EnvironmentError) and
# the invalid mode shows up in backups of /proc for some reason
(exc[0] in ('invalid mode: rb', 'Not a gzipped file') or
errno.errorcode.has_key(exc[0]) and
errno.errorcode[exc[0]] in ('EPERM', 'ENOENT', 'EACCES', 'EBUSY',
'EEXIST', 'ENOTDIR', 'EILSEQ',
'ENAMETOOLONG', 'EINTR', 'ESTALE',
'ENOTEMPTY', 'EIO', 'ETXTBSY',
'ESRCH', 'EINVAL', 'EDEADLOCK',
'EDEADLK', 'EOPNOTSUPP', 'ETIMEDOUT'))):
return 1
return 0
def is_routine_fatal(exc):
"""Return string if exception is non-error unrecoverable, None otherwise
Used to suppress a stack trace for exceptions like keyboard
interrupts or connection drops. Return value is string to use as
an exit message.
"""
if isinstance(exc, exceptions.KeyboardInterrupt):
return "User abort"
elif isinstance(exc, connection.ConnectionError):
return "Lost connection to the remote system"
elif isinstance(exc, SignalException):
return "Killed with signal %s" % (exc,)
elif isinstance(exc, EnvironmentError) and exc.errno == errno.ENOTCONN:
return ("Filesystem reports connection failure:\n%s" % exc)
return None
def get_error_handler(error_type):
"""Return error handler function that can be used above
Function will just log error to the error_log and then return
None. First two arguments must be the exception and then an rp
(from which the filename will be extracted).
"""
def error_handler(exc, rp, *args):
log.ErrorLog.write_if_open(error_type, rp, exc)
return 0
return error_handler
def listrp(rp):
"""Like rp.listdir() but return [] if error, and sort results"""
def error_handler(exc):
log.Log("Error listing directory %s" % rp.path, 2)
return []
dir_listing = check_common_error(error_handler, rp.listdir)
dir_listing.sort()
return dir_listing
def signal_handler(signum, frame):
"""This is called when signal signum is caught"""
raise SignalException(signum)
def install_signal_handlers():
"""Install signal handlers on current connection"""
signals = [signal.SIGTERM, signal.SIGINT]
try:
signals.extend([signal.SIGHUP, signal.SIGQUIT])
except AttributeError:
pass
for signum in signals:
signal.signal(signum, signal_handler)
class SignalException(Exception):
"""SignalException(signum) means signal signum has been received"""
pass
class TracebackArchive:
"""Save last 10 caught exceptions, so they can be printed if fatal"""
_traceback_strings = []
def add(cls, extra_args = []):
"""Add most recent exception to archived list
If extra_args are present, convert to strings and add them as
extra information to same traceback archive.
"""
cls._traceback_strings.append(log.Log.exception_to_string(extra_args))
if len(cls._traceback_strings) > 10:
cls._traceback_strings = cls._traceback_strings[:10]
def log(cls):
"""Print all exception information to log file"""
if cls._traceback_strings:
log.Log("------------ Old traceback info -----------\n%s\n"
"-------------------------------------------" %
("\n".join(cls._traceback_strings),), 3)
static.MakeClass(TracebackArchive)
|