Back to index

apport  2.4
Functions | Variables
apport.fileutils Namespace Reference

Functions

def allowed_to_report
def find_package_desktopfile
def likely_packaged
def find_file_package
def seen_report
def mark_report_upload
def mark_hanging_process
def mark_report_seen
def get_all_reports
def get_new_reports
def get_all_system_reports
def get_new_system_reports
def delete_report
def get_recent_crashes
def make_report_path
def check_files_md5
def get_config

Variables

tuple report_dir = os.environ.get('APPORT_REPORT_DIR', '/var/crash')
string _config_file = '~/.config/apport/settings'
string _whoopsie_config_file = '/etc/default/whoopsie'

Detailed Description

Functions to manage apport problem report files.

Function Documentation

Check whether crash reporting is enabled.

Definition at line 31 of file fileutils.py.

00031 
00032 def allowed_to_report():
00033     '''Check whether crash reporting is enabled.'''
00034 
00035     return get_config('General', 'report_crashes', default=True,
00036                       path=_whoopsie_config_file, bool=True)
00037 

Here is the call graph for this function:

Here is the caller graph for this function:

Check file integrity against md5 sum file.

sumfile must be md5sum(1) format (relative to /).

Return a list of files that don't match.

Definition at line 264 of file fileutils.py.

00264 
00265 def check_files_md5(sumfile):
00266     '''Check file integrity against md5 sum file.
00267 
00268     sumfile must be md5sum(1) format (relative to /).
00269 
00270     Return a list of files that don't match.
00271     '''
00272     assert os.path.exists(sumfile)
00273     m = subprocess.Popen(['/usr/bin/md5sum', '-c', sumfile],
00274                          stdout=subprocess.PIPE, stderr=subprocess.PIPE,
00275                          cwd='/', env={})
00276     out = m.communicate()[0].decode()
00277 
00278     # if md5sum succeeded, don't bother parsing the output
00279     if m.returncode == 0:
00280         return []
00281 
00282     mismatches = []
00283     for l in out.splitlines():
00284         if l.endswith('FAILED'):
00285             mismatches.append(l.rsplit(':', 1)[0])
00286 
00287     return mismatches
00288 

Here is the caller graph for this function:

Delete the given report file.

If unlinking the file fails due to a permission error (if report_dir is not
writable to normal users), the file will be truncated to 0 bytes instead.

Definition at line 213 of file fileutils.py.

00213 
00214 def delete_report(report):
00215     '''Delete the given report file.
00216 
00217     If unlinking the file fails due to a permission error (if report_dir is not
00218     writable to normal users), the file will be truncated to 0 bytes instead.
00219     '''
00220     try:
00221         os.unlink(report)
00222     except OSError:
00223         with open(report, 'w') as f:
00224             f.truncate(0)
00225 

Here is the caller graph for this function:

Return the package that ships the given file.

Return None if no package ships it.

Definition at line 79 of file fileutils.py.

00079 
00080 def find_file_package(file):
00081     '''Return the package that ships the given file.
00082 
00083     Return None if no package ships it.
00084     '''
00085     # resolve symlinks in directories
00086     (dir, name) = os.path.split(file)
00087     resolved_dir = os.path.realpath(dir)
00088     if os.path.isdir(resolved_dir):
00089         file = os.path.join(resolved_dir, name)
00090 
00091     if not likely_packaged(file):
00092         return None
00093 
00094     return packaging.get_file_package(file)
00095 

Here is the call graph for this function:

Here is the caller graph for this function:

Return a package's .desktop file.

If given package is installed and has a single .desktop file, return the
path to it, otherwise return None.

Definition at line 38 of file fileutils.py.

00038 
00039 def find_package_desktopfile(package):
00040     '''Return a package's .desktop file.
00041 
00042     If given package is installed and has a single .desktop file, return the
00043     path to it, otherwise return None.
00044     '''
00045     if package is None:
00046         return None
00047 
00048     desktopfile = None
00049 
00050     for line in packaging.get_files(package):
00051         if line.endswith('.desktop'):
00052             if desktopfile:
00053                 return None  # more than one
00054             else:
00055                 desktopfile = line
00056 
00057     return desktopfile
00058 

Here is the caller graph for this function:

Return a list with all report files accessible to the calling user.

Definition at line 153 of file fileutils.py.

00153 
00154 def get_all_reports():
00155     '''Return a list with all report files accessible to the calling user.'''
00156 
00157     reports = []
00158     for r in glob.glob(os.path.join(report_dir, '*.crash')):
00159         try:
00160             if os.path.getsize(r) > 0 and os.access(r, os.R_OK):
00161                 reports.append(r)
00162         except OSError:
00163             # race condition, can happen if report disappears between glob and
00164             # stat
00165             pass
00166     return reports
00167 

Here is the caller graph for this function:

Get all system reports.

Return a list with all report files which belong to a system user (i. e.
uid < 500 according to LSB).

Definition at line 186 of file fileutils.py.

00186 
00187 def get_all_system_reports():
00188     '''Get all system reports.
00189 
00190     Return a list with all report files which belong to a system user (i. e.
00191     uid < 500 according to LSB).
00192     '''
00193     reports = []
00194     for r in glob.glob(os.path.join(report_dir, '*.crash')):
00195         try:
00196             if os.path.getsize(r) > 0 and os.stat(r).st_uid < 500:
00197                 reports.append(r)
00198         except OSError:
00199             # race condition, can happen if report disappears between glob and
00200             # stat
00201             pass
00202     return reports
00203 

Here is the caller graph for this function:

def apport.fileutils.get_config (   section,
  setting,
  default = None,
  path = None,
  bool = False 
)
Return a setting from user configuration.

This is read from ~/.config/apport/settings or path. If bool is True, the
value is interpreted as a boolean.

Definition at line 289 of file fileutils.py.

00289 
00290 def get_config(section, setting, default=None, path=None, bool=False):
00291     '''Return a setting from user configuration.
00292 
00293     This is read from ~/.config/apport/settings or path. If bool is True, the
00294     value is interpreted as a boolean.
00295     '''
00296     if not get_config.config:
00297         get_config.config = ConfigParser()
00298         if path:
00299             get_config.config.read(path)
00300         else:
00301             get_config.config.read(os.path.expanduser(_config_file))
00302 
00303     try:
00304         if bool:
00305             return get_config.config.getboolean(section, setting)
00306         else:
00307             return get_config.config.get(section, setting)
00308     except (NoOptionError, NoSectionError):
00309         return default
00310 
00311 get_config.config = None

Here is the caller graph for this function:

Get new reports for calling user.

Return a list with all report files which have not yet been processed
and are accessible to the calling user.

Definition at line 168 of file fileutils.py.

00168 
00169 def get_new_reports():
00170     '''Get new reports for calling user.
00171 
00172     Return a list with all report files which have not yet been processed
00173     and are accessible to the calling user.
00174     '''
00175     reports = []
00176     for r in get_all_reports():
00177         try:
00178             if not seen_report(r):
00179                 reports.append(r)
00180         except OSError:
00181             # race condition, can happen if report disappears between glob and
00182             # stat
00183             pass
00184     return reports
00185 

Here is the call graph for this function:

Here is the caller graph for this function:

Get new system reports.

Return a list with all report files which have not yet been processed
and belong to a system user (i. e. uid < 500 according to LSB).

Definition at line 204 of file fileutils.py.

00204 
00205 def get_new_system_reports():
00206     '''Get new system reports.
00207 
00208     Return a list with all report files which have not yet been processed
00209     and belong to a system user (i. e. uid < 500 according to LSB).
00210     '''
00211     return [r for r in get_all_system_reports() if not seen_report(r)]
00212 

Here is the call graph for this function:

Here is the caller graph for this function:

Return the number of recent crashes for the given report file.

Return the number of recent crashes (currently, crashes which happened more
than 24 hours ago are discarded).

Definition at line 226 of file fileutils.py.

00226 
00227 def get_recent_crashes(report):
00228     '''Return the number of recent crashes for the given report file.
00229 
00230     Return the number of recent crashes (currently, crashes which happened more
00231     than 24 hours ago are discarded).
00232     '''
00233     pr = ProblemReport()
00234     pr.load(report, False)
00235     try:
00236         count = int(pr['CrashCounter'])
00237         report_time = time.mktime(time.strptime(pr['Date']))
00238         cur_time = time.mktime(time.localtime())
00239         # discard reports which are older than 24 hours
00240         if cur_time - report_time > 24 * 3600:
00241             return 0
00242         return count
00243     except (ValueError, KeyError):
00244         return 0
00245 

Here is the caller graph for this function:

Check whether the given file is likely to belong to a package.

This is semi-decidable: A return value of False is definitive, a True value
is only a guess which needs to be checked with find_file_package().
However, this function is very fast and does not access the package
database.

Definition at line 59 of file fileutils.py.

00059 
00060 def likely_packaged(file):
00061     '''Check whether the given file is likely to belong to a package.
00062 
00063     This is semi-decidable: A return value of False is definitive, a True value
00064     is only a guess which needs to be checked with find_file_package().
00065     However, this function is very fast and does not access the package
00066     database.
00067     '''
00068     pkg_whitelist = ['/bin/', '/boot', '/etc/', '/initrd', '/lib', '/sbin/',
00069                      '/usr/', '/var']  # packages only ship executables in these directories
00070 
00071     whitelist_match = False
00072     for i in pkg_whitelist:
00073         if file.startswith(i):
00074             whitelist_match = True
00075             break
00076     return whitelist_match and not file.startswith('/usr/local/') and not \
00077         file.startswith('/var/lib/')
00078 

Here is the caller graph for this function:

def apport.fileutils.make_report_path (   report,
  uid = None 
)
Construct a canonical pathname for the given report.

If uid is not given, it defaults to the uid of the current process.

Definition at line 246 of file fileutils.py.

00246 
00247 def make_report_path(report, uid=None):
00248     '''Construct a canonical pathname for the given report.
00249 
00250     If uid is not given, it defaults to the uid of the current process.
00251     '''
00252     if 'ExecutablePath' in report:
00253         subject = report['ExecutablePath'].replace('/', '_')
00254     elif 'Package' in report:
00255         subject = report['Package'].split(None, 1)[0]
00256     else:
00257         raise ValueError('report has neither ExecutablePath nor Package attribute')
00258 
00259     if not uid:
00260         uid = os.getuid()
00261 
00262     return os.path.join(report_dir, '%s.%s.crash' % (subject, str(uid)))
00263 

Here is the caller graph for this function:

def apport.fileutils.mark_hanging_process (   report,
  pid 
)

Definition at line 109 of file fileutils.py.

00109 
00110 def mark_hanging_process(report, pid):
00111     if 'ExecutablePath' in report:
00112         subject = report['ExecutablePath'].replace('/', '_')
00113     else:
00114         raise ValueError('report does not have the ExecutablePath attribute')
00115 
00116     uid = os.getuid()
00117     base = '%s.%s.%s.hanging' % (subject, str(uid), pid)
00118     path = os.path.join(report_dir, base)
00119     with open(path, 'a'):
00120         pass
00121 

Here is the caller graph for this function:

Mark given report file as seen.

Definition at line 122 of file fileutils.py.

00122 
00123 def mark_report_seen(report):
00124     '''Mark given report file as seen.'''
00125 
00126     st = os.stat(report)
00127     try:
00128         os.utime(report, (st.st_mtime, st.st_mtime - 1))
00129     except OSError:
00130         # file is probably not our's, so do it the slow and boring way
00131         # change the file's access time until it stat's different than the mtime.
00132         # This might take a while if we only have 1-second resolution. Time out
00133         # after 1.2 seconds.
00134         timeout = 12
00135         while timeout > 0:
00136             f = open(report)
00137             f.read(1)
00138             f.close()
00139             try:
00140                 st = os.stat(report)
00141             except OSError:
00142                 return
00143 
00144             if st.st_atime > st.st_mtime:
00145                 break
00146             time.sleep(0.1)
00147             timeout -= 1
00148 
00149         if timeout == 0:
00150             # happens on noatime mounted partitions; just give up and delete
00151             delete_report(report)
00152 

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 103 of file fileutils.py.

00103 
00104 def mark_report_upload(report):
00105     report = '%s.upload' % report.rsplit('.', 1)[0]
00106     with open(report, 'a'):
00107         pass
00108 

Here is the caller graph for this function:

def apport.fileutils.seen_report (   report)
Check whether the report file has already been processed earlier.

Definition at line 96 of file fileutils.py.

00096 
00097 def seen_report(report):
00098     '''Check whether the report file has already been processed earlier.'''
00099 
00100     st = os.stat(report)
00101     return (st.st_atime > st.st_mtime) or (st.st_size == 0)
00102 

Here is the caller graph for this function:


Variable Documentation

string apport.fileutils._config_file = '~/.config/apport/settings'

Definition at line 27 of file fileutils.py.

string apport.fileutils._whoopsie_config_file = '/etc/default/whoopsie'

Definition at line 28 of file fileutils.py.

tuple apport.fileutils.report_dir = os.environ.get('APPORT_REPORT_DIR', '/var/crash')

Definition at line 25 of file fileutils.py.