Back to index

apport  2.4
Functions | Variables
apport.hookutils Namespace Reference

Functions

def path_to_key
def attach_file_if_exists
def read_file
def attach_file
def attach_conffiles
def attach_upstart_overrides
def attach_dmesg
def attach_dmi
def attach_hardware
def attach_alsa_old
def attach_alsa
def command_available
def command_output
def _root_command_prefix
def root_command_output
def attach_root_command_outputs
def recent_syslog
def recent_logfile
def xsession_errors
def pci_devices
def usb_devices
def files_in_package
def attach_gconf
def attach_gsettings_schema
def attach_gsettings_package
def attach_network
def attach_wifi
def attach_printing
def attach_mac_events
def attach_related_packages
def package_versions
def shared_libraries
def links_with_shared_library
def _get_module_license
def nonfree_kernel_modules
def __drm_con_info
def attach_drm_info
def in_session_of_problem
def attach_default_grub

Variables

string _path_key_trans = ''
int PCI_MASS_STORAGE = 0x01
int PCI_NETWORK = 0x02
int PCI_DISPLAY = 0x03
int PCI_MULTIMEDIA = 0x04
int PCI_MEMORY = 0x05
int PCI_BRIDGE = 0x06
int PCI_SIMPLE_COMMUNICATIONS = 0x07
int PCI_BASE_SYSTEM_PERIPHERALS = 0x08
int PCI_INPUT_DEVICES = 0x09
int PCI_DOCKING_STATIONS = 0x0a
int PCI_PROCESSORS = 0x0b
int PCI_SERIAL_BUS = 0x0c

Detailed Description

Convenience functions for use in package hooks.

Function Documentation

def apport.hookutils.__drm_con_info (   con) [private]

Definition at line 817 of file hookutils.py.

00817 
00818 def __drm_con_info(con):
00819     info = ''
00820     for f in os.listdir(con):
00821         path = os.path.join(con, f)
00822         if f == 'uevent' or not os.path.isfile(path):
00823             continue
00824         val = open(path).read().strip()
00825         # format some well-known attributes specially
00826         if f == 'modes':
00827             val = val.replace('\n', ' ')
00828         if f == 'edid':
00829             val = base64.b64encode(val)
00830             f += '-base64'
00831         info += '%s: %s\n' % (f, val)
00832     return info
00833 

Here is the caller graph for this function:

def apport.hookutils._get_module_license (   module) [private]
Return the license for a given kernel module.

Definition at line 778 of file hookutils.py.

00778 
00779 def _get_module_license(module):
00780     '''Return the license for a given kernel module.'''
00781 
00782     try:
00783         modinfo = subprocess.Popen(['/sbin/modinfo', module],
00784                                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
00785         out = modinfo.communicate()[0].decode('UTF-8')
00786         if modinfo.returncode != 0:
00787             return 'invalid'
00788     except OSError:
00789         return None
00790     for l in out.splitlines():
00791         fields = l.split(':', 1)
00792         if len(fields) < 2:
00793             continue
00794         if fields[0] == 'license':
00795             return fields[1].strip()
00796 
00797     return None
00798 

Here is the caller graph for this function:

Definition at line 374 of file hookutils.py.

00374 
00375 def _root_command_prefix():
00376     if os.getuid() == 0:
00377         prefix = []
00378     elif os.getenv('DISPLAY') and \
00379             subprocess.call(['which', 'kdesudo'], stdout=subprocess.PIPE,
00380                             stderr=subprocess.PIPE) == 0 and \
00381             subprocess.call(['pgrep', '-x', '-u', str(os.getuid()), 'ksmserver'],
00382                             stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
00383         prefix = ['kdesudo', '--desktop', '/usr/share/applications/apport-kde-mime.desktop',
00384                   '--', 'env', '-u', 'LANGUAGE', 'LC_MESSAGES=C']
00385     elif os.getenv('DISPLAY') and \
00386             subprocess.call(['which', 'gksu'], stdout=subprocess.PIPE,
00387                             stderr=subprocess.PIPE) == 0 and \
00388             subprocess.call(['pgrep', '-x', '-u', str(os.getuid()), 'gnome-panel|gconfd-2'],
00389                             stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0:
00390         prefix = ['gksu', '-D', 'Apport', '--', 'env', '-u', 'LANGUAGE', 'LC_MESSAGES=C']
00391     else:
00392         prefix = ['sudo', 'LC_MESSAGES=C', 'LANGUAGE=']
00393 
00394     return prefix
00395 

Here is the caller graph for this function:

def apport.hookutils.attach_alsa (   report)
Attach ALSA subsystem information to the report.

Definition at line 309 of file hookutils.py.

00309 
00310 def attach_alsa(report):
00311     '''Attach ALSA subsystem information to the report.
00312     '''
00313     if os.path.exists('/usr/share/alsa-base/alsa-info.sh'):
00314         report['AlsaInfo'] = command_output(['/usr/share/alsa-base/alsa-info.sh', '--stdout', '--no-upload'])
00315     else:
00316         attach_alsa_old(report)
00317 
00318     report['AudioDevicesInUse'] = command_output(
00319         ['fuser', '-v'] + glob.glob('/dev/dsp*') + glob.glob('/dev/snd/*') + glob.glob('/dev/seq*'))
00320 
00321     if os.path.exists('/usr/bin/pacmd'):
00322         report['PulseList'] = command_output(['pacmd', 'list'])
00323 
00324     attach_dmi(report)
00325     attach_dmesg(report)
00326 

Here is the call graph for this function:

Here is the caller graph for this function:

(loosely based on http://www.alsa-project.org/alsa-info.sh)
for systems where alsa-info is not installed (i e, *buntu 12.04 and earlier)

Definition at line 264 of file hookutils.py.

00264 
00265 def attach_alsa_old(report):
00266     ''' (loosely based on http://www.alsa-project.org/alsa-info.sh)
00267     for systems where alsa-info is not installed (i e, *buntu 12.04 and earlier)
00268     '''
00269     attach_file_if_exists(report, os.path.expanduser('~/.asoundrc'),
00270                           'UserAsoundrc')
00271     attach_file_if_exists(report, os.path.expanduser('~/.asoundrc.asoundconf'),
00272                           'UserAsoundrcAsoundconf')
00273     attach_file_if_exists(report, '/etc/asound.conf')
00274     attach_file_if_exists(report, '/proc/asound/version', 'AlsaVersion')
00275     attach_file(report, '/proc/cpuinfo', 'ProcCpuinfo')
00276 
00277     report['AlsaDevices'] = command_output(['ls', '-l', '/dev/snd/'])
00278     report['AplayDevices'] = command_output(['aplay', '-l'])
00279     report['ArecordDevices'] = command_output(['arecord', '-l'])
00280 
00281     report['PciMultimedia'] = pci_devices(PCI_MULTIMEDIA)
00282 
00283     cards = []
00284     if os.path.exists('/proc/asound/cards'):
00285         with open('/proc/asound/cards') as fd:
00286             for line in fd:
00287                 if ']:' in line:
00288                     fields = line.lstrip().split()
00289                     cards.append(int(fields[0]))
00290 
00291     for card in cards:
00292         key = 'Card%d.Amixer.info' % card
00293         report[key] = command_output(['amixer', '-c', str(card), 'info'])
00294         key = 'Card%d.Amixer.values' % card
00295         report[key] = command_output(['amixer', '-c', str(card)])
00296 
00297         for codecpath in glob.glob('/proc/asound/card%d/codec*' % card):
00298             if os.path.isfile(codecpath):
00299                 codec = os.path.basename(codecpath)
00300                 key = 'Card%d.Codecs.%s' % (card, path_to_key(codec))
00301                 attach_file(report, codecpath, key=key)
00302             elif os.path.isdir(codecpath):
00303                 codec = os.path.basename(codecpath)
00304                 for name in os.listdir(codecpath):
00305                     path = os.path.join(codecpath, name)
00306                     key = 'Card%d.Codecs.%s.%s' % (card, path_to_key(codec), path_to_key(name))
00307                     attach_file(report, path, key)
00308 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_conffiles (   report,
  package,
  conffiles = None,
  ui = None 
)
Attach information about any modified or deleted conffiles.

If conffiles is given, only this subset will be attached. If ui is given,
ask whether the contents of the file may be added to the report; if this is
denied, or there is no UI, just mark it as "modified" in the report.

Definition at line 120 of file hookutils.py.

00120 
00121 def attach_conffiles(report, package, conffiles=None, ui=None):
00122     '''Attach information about any modified or deleted conffiles.
00123 
00124     If conffiles is given, only this subset will be attached. If ui is given,
00125     ask whether the contents of the file may be added to the report; if this is
00126     denied, or there is no UI, just mark it as "modified" in the report.
00127     '''
00128     modified = packaging.get_modified_conffiles(package)
00129 
00130     for path, contents in modified.items():
00131         if conffiles and path not in conffiles:
00132             continue
00133 
00134         key = 'modified.conffile.' + path_to_key(path)
00135         if contents == '[deleted]':
00136             report[key] = contents
00137             continue
00138 
00139         if ui:
00140             response = ui.yesno('It seems you have modified the contents of "%s".  Would you like to add the contents of it to your bug report?' % path)
00141             if response:
00142                 report[key] = contents
00143             else:
00144                 report[key] = '[modified]'
00145         else:
00146             report[key] = '[modified]'
00147 
00148         mtime = datetime.datetime.fromtimestamp(os.stat(path).st_mtime)
00149         report['mtime.conffile.' + path_to_key(path)] = mtime.isoformat()
00150 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_default_grub (   report,
  key = None 
)
attach /etc/default/grub after filtering out password lines

Definition at line 898 of file hookutils.py.

00898 
00899 def attach_default_grub(report, key=None):
00900     '''attach /etc/default/grub after filtering out password lines'''
00901 
00902     path = '/etc/default/grub'
00903     if not key:
00904         key = path_to_key(path)
00905 
00906     if os.path.exists(path):
00907         with open(path, 'r') as f:
00908             filtered = [l if not l.startswith('password')
00909                         else '### PASSWORD LINE REMOVED ###'
00910                         for l in f.readlines()]
00911             report[key] = ''.join(filtered)

Here is the call graph for this function:

Here is the caller graph for this function:

Attach information from the kernel ring buffer (dmesg).

This will not overwrite already existing information.

Definition at line 166 of file hookutils.py.

00166 
00167 def attach_dmesg(report):
00168     '''Attach information from the kernel ring buffer (dmesg).
00169 
00170     This will not overwrite already existing information.
00171     '''
00172     try:
00173         if not report.get('BootDmesg', '').strip():
00174             with open('/var/log/dmesg') as f:
00175                 report['BootDmesg'] = f.read()
00176     except IOError:
00177         pass
00178     if not report.get('CurrentDmesg', '').strip():
00179         dmesg = command_output(['sh', '-c', 'dmesg | comm -13 --nocheck-order /var/log/dmesg -'])
00180         # if an initial message was truncated by the ring buffer, skip over it
00181         first_newline = dmesg.find('\n[')
00182         if first_newline != -1:
00183             dmesg = dmesg[first_newline + 1:]
00184         report['CurrentDmesg'] = dmesg
00185 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_dmi (   report)

Definition at line 186 of file hookutils.py.

00186 
00187 def attach_dmi(report):
00188     dmi_dir = '/sys/class/dmi/id'
00189     if os.path.isdir(dmi_dir):
00190         for f in os.listdir(dmi_dir):
00191             p = '%s/%s' % (dmi_dir, f)
00192             st = os.stat(p)
00193             # ignore the root-only ones, since they have serial numbers
00194             if not stat.S_ISREG(st.st_mode) or (st.st_mode & 4 == 0):
00195                 continue
00196             if f in ('subsystem', 'uevent'):
00197                 continue
00198 
00199             try:
00200                 with open(p) as fd:
00201                     value = fd.read().strip()
00202             except (OSError, IOError):
00203                 continue
00204             if value:
00205                 report['dmi.' + f.replace('_', '.')] = value
00206 

Here is the caller graph for this function:

Add information about DRM hardware.

Collect information from /sys/class/drm/.

Definition at line 834 of file hookutils.py.

00834 
00835 def attach_drm_info(report):
00836     '''Add information about DRM hardware.
00837 
00838     Collect information from /sys/class/drm/.
00839     '''
00840     drm_dir = '/sys/class/drm'
00841     if not os.path.isdir(drm_dir):
00842         return
00843     for f in os.listdir(drm_dir):
00844         con = os.path.join(drm_dir, f)
00845         if os.path.exists(os.path.join(con, 'enabled')):
00846             # DRM can set an arbitrary string for its connector paths.
00847             report['DRM.' + path_to_key(f)] = __drm_con_info(con)
00848 

Here is the call graph for this function:

def apport.hookutils.attach_file (   report,
  path,
  key = None,
  overwrite = True,
  force_unicode = False 
)
Attach a file to the report.

If key is not specified, the key name will be derived from the file
name with path_to_key().

If overwrite is True, an existing key will be updated. If it is False, a
new key with '_' appended will be added instead.

If the contents is valid UTF-8, or force_unicode is True, then the value
will a string, otherwise it will be bytes.

Definition at line 98 of file hookutils.py.

00098 
00099 def attach_file(report, path, key=None, overwrite=True, force_unicode=False):
00100     '''Attach a file to the report.
00101 
00102     If key is not specified, the key name will be derived from the file
00103     name with path_to_key().
00104 
00105     If overwrite is True, an existing key will be updated. If it is False, a
00106     new key with '_' appended will be added instead.
00107 
00108     If the contents is valid UTF-8, or force_unicode is True, then the value
00109     will a string, otherwise it will be bytes.
00110     '''
00111     if not key:
00112         key = path_to_key(path)
00113 
00114     # Do not clobber existing keys
00115     if not overwrite:
00116         while key in report:
00117             key += '_'
00118     report[key] = read_file(path, force_unicode=force_unicode)
00119 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_file_if_exists (   report,
  path,
  key = None,
  overwrite = True,
  force_unicode = False 
)
Attach file contents if file exists.

If key is not specified, the key name will be derived from the file
name with path_to_key().

If overwrite is True, an existing key will be updated. If it is False, a
new key with '_' appended will be added instead.

If the contents is valid UTF-8, or force_unicode is True, then the value
will a string, otherwise it will be bytes.

Definition at line 57 of file hookutils.py.

00057 
00058 def attach_file_if_exists(report, path, key=None, overwrite=True, force_unicode=False):
00059     '''Attach file contents if file exists.
00060 
00061     If key is not specified, the key name will be derived from the file
00062     name with path_to_key().
00063 
00064     If overwrite is True, an existing key will be updated. If it is False, a
00065     new key with '_' appended will be added instead.
00066 
00067     If the contents is valid UTF-8, or force_unicode is True, then the value
00068     will a string, otherwise it will be bytes.
00069     '''
00070     if not key:
00071         key = path_to_key(path)
00072 
00073     if os.path.exists(path):
00074         attach_file(report, path, key, overwrite, force_unicode)
00075 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_gconf (   report,
  package 
)
Obsolete

Definition at line 573 of file hookutils.py.

00573 
00574 def attach_gconf(report, package):
00575     '''Obsolete'''
00576 
00577     # keeping a no-op function for some time to not break hooks
00578     pass
00579 

def apport.hookutils.attach_gsettings_package (   report,
  package 
)
Attach user-modified gsettings keys of all schemas in a package.

Definition at line 613 of file hookutils.py.

00613 
00614 def attach_gsettings_package(report, package):
00615     '''Attach user-modified gsettings keys of all schemas in a package.'''
00616 
00617     for schema_file in files_in_package(package, '/usr/share/glib-2.0/schemas/*.gschema.xml'):
00618         schema = os.path.basename(schema_file)[:-12]
00619         attach_gsettings_schema(report, schema)
00620 

Here is the call graph for this function:

def apport.hookutils.attach_gsettings_schema (   report,
  schema 
)
Attach user-modified gsttings keys of a schema.

Definition at line 580 of file hookutils.py.

00580 
00581 def attach_gsettings_schema(report, schema):
00582     '''Attach user-modified gsttings keys of a schema.'''
00583 
00584     cur_value = report.get('GsettingsChanges', '')
00585 
00586     defaults = {}  # schema -> key ->  value
00587     env = os.environ.copy()
00588     env['XDG_CONFIG_HOME'] = '/nonexisting'
00589     gsettings = subprocess.Popen(['gsettings', 'list-recursively', schema],
00590                                  env=env, stdout=subprocess.PIPE)
00591     for l in gsettings.stdout:
00592         try:
00593             (schema, key, value) = l.split(None, 2)
00594             value = value.rstrip()
00595         except ValueError:
00596             continue  # invalid line
00597         defaults.setdefault(schema, {})[key] = value
00598 
00599     gsettings = subprocess.Popen(['gsettings', 'list-recursively', schema],
00600                                  stdout=subprocess.PIPE)
00601     for l in gsettings.stdout:
00602         try:
00603             (schema, key, value) = l.split(None, 2)
00604             value = value.rstrip()
00605         except ValueError:
00606             continue  # invalid line
00607 
00608         if value != defaults.get(schema, {}).get(key, ''):
00609             cur_value += '%s %s %s\n' % (schema, key, value)
00610 
00611     report['GsettingsChanges'] = cur_value
00612 

Here is the caller graph for this function:

Attach a standard set of hardware-related data to the report, including:

- kernel dmesg (boot and current)
- /proc/interrupts
- /proc/cpuinfo
- /proc/cmdline
- /proc/modules
- lspci -vvnn
- lsusb
- devices from udev
- DMI information from /sys
- prtconf (sparc)
- pccardctl status/ident

Definition at line 207 of file hookutils.py.

00207 
00208 def attach_hardware(report):
00209     '''Attach a standard set of hardware-related data to the report, including:
00210 
00211     - kernel dmesg (boot and current)
00212     - /proc/interrupts
00213     - /proc/cpuinfo
00214     - /proc/cmdline
00215     - /proc/modules
00216     - lspci -vvnn
00217     - lsusb
00218     - devices from udev
00219     - DMI information from /sys
00220     - prtconf (sparc)
00221     - pccardctl status/ident
00222     '''
00223     attach_dmesg(report)
00224 
00225     attach_file(report, '/proc/interrupts', 'ProcInterrupts')
00226     attach_file(report, '/proc/cpuinfo', 'ProcCpuinfo')
00227     attach_file(report, '/proc/cmdline', 'ProcKernelCmdLine')
00228     attach_file(report, '/var/log/udev', 'UdevLog', force_unicode=True)
00229 
00230     if os.path.exists('/sys/bus/pci'):
00231         report['Lspci'] = command_output(['lspci', '-vvnn'])
00232     report['Lsusb'] = command_output(['lsusb'])
00233     report['ProcModules'] = command_output(['sort', '/proc/modules'])
00234     report['UdevDb'] = command_output(['udevadm', 'info', '--export-db'])
00235 
00236     # anonymize partition labels
00237     l = report['UdevLog']
00238     l = re.sub('ID_FS_LABEL=(.*)', 'ID_FS_LABEL=<hidden>', l)
00239     l = re.sub('ID_FS_LABEL_ENC=(.*)', 'ID_FS_LABEL_ENC=<hidden>', l)
00240     l = re.sub('by-label/(.*)', 'by-label/<hidden>', l)
00241     l = re.sub('ID_FS_LABEL=(.*)', 'ID_FS_LABEL=<hidden>', l)
00242     l = re.sub('ID_FS_LABEL_ENC=(.*)', 'ID_FS_LABEL_ENC=<hidden>', l)
00243     l = re.sub('by-label/(.*)', 'by-label/<hidden>', l)
00244     report['UdevLog'] = l
00245 
00246     attach_dmi(report)
00247 
00248     # Use the hardware information to create a machine type.
00249     if 'dmi.sys.vendor' in report and 'dmi.product.name' in report:
00250         report['MachineType'] = '%s %s' % (report['dmi.sys.vendor'],
00251                                            report['dmi.product.name'])
00252 
00253     if command_available('prtconf'):
00254         report['Prtconf'] = command_output(['prtconf'])
00255 
00256     if command_available('pccardctl'):
00257         out = command_output(['pccardctl', 'status']).strip()
00258         if out:
00259             report['PccardctlStatus'] = out
00260         out = command_output(['pccardctl', 'ident']).strip()
00261         if out:
00262             report['PccardctlIdent'] = out
00263 

Here is the call graph for this function:

Here is the caller graph for this function:

Attach MAC information and events to the report.

Definition at line 676 of file hookutils.py.

00676 
00677 def attach_mac_events(report):
00678     '''Attach MAC information and events to the report.'''
00679 
00680     mac_regex = 'audit\(|apparmor|selinux|security'
00681     mac_re = re.compile(mac_regex, re.IGNORECASE)
00682     aa_denied_regex = 'apparmor="DENIED"'
00683     aa_denied_re = re.compile(aa_denied_regex, re.IGNORECASE)
00684 
00685     if os.path.exists('/var/log/kern.log'):
00686         report['KernLog'] = recent_logfile('/var/log/kern.log', mac_re)
00687     elif os.path.exists('/var/log/messages'):
00688         report['KernLog'] = recent_logfile('/var/log/messages', mac_re)
00689 
00690     if os.path.exists('/var/run/auditd.pid'):
00691         attach_root_command_outputs(report, {'AuditLog': 'egrep "' + mac_regex + '" /var/log/audit/audit.log'})
00692 
00693     attach_file(report, '/proc/version_signature', 'ProcVersionSignature')
00694     attach_file(report, '/proc/cmdline', 'ProcCmdline')
00695 
00696     if re.search(aa_denied_re, report.get('KernLog', '')) or re.search(aa_denied_re, report.get('AuditLog', '')):
00697         tags = report.get('Tags', '')
00698         if tags:
00699             tags += ' '
00700         report['Tags'] = tags + 'apparmor'
00701 

Here is the call graph for this function:

Attach generic network-related information to report.

Definition at line 621 of file hookutils.py.

00621 
00622 def attach_network(report):
00623     '''Attach generic network-related information to report.'''
00624 
00625     report['IpRoute'] = command_output(['ip', 'route'])
00626     report['IpAddr'] = command_output(['ip', 'addr'])
00627     report['PciNetwork'] = pci_devices(PCI_NETWORK)
00628     attach_file_if_exists(report, '/etc/network/interfaces', key='IfupdownConfig')
00629 
00630     for var in ('http_proxy', 'ftp_proxy', 'no_proxy'):
00631         if var in os.environ:
00632             report[var] = os.environ[var]
00633 

Here is the call graph for this function:

Here is the caller graph for this function:

Attach printing information to the report.

Based on http://wiki.ubuntu.com/PrintingBugInfoScript.

Definition at line 649 of file hookutils.py.

00649 
00650 def attach_printing(report):
00651     '''Attach printing information to the report.
00652 
00653     Based on http://wiki.ubuntu.com/PrintingBugInfoScript.
00654     '''
00655     attach_file_if_exists(report, '/etc/papersize', 'Papersize')
00656     attach_file_if_exists(report, '/var/log/cups/error_log', 'CupsErrorLog')
00657     report['Locale'] = command_output(['locale'])
00658     report['Lpstat'] = command_output(['lpstat', '-v'])
00659 
00660     ppds = glob.glob('/etc/cups/ppd/*.ppd')
00661     if ppds:
00662         nicknames = command_output(['fgrep', '-H', '*NickName'] + ppds)
00663         report['PpdFiles'] = re.sub('/etc/cups/ppd/(.*).ppd:\*NickName: *"(.*)"', '\g<1>: \g<2>', nicknames)
00664 
00665     report['PrintingPackages'] = package_versions(
00666         'foo2zjs', 'foomatic-db', 'foomatic-db-engine',
00667         'foomatic-db-gutenprint', 'foomatic-db-hpijs', 'foomatic-filters',
00668         'foomatic-gui', 'hpijs', 'hplip', 'm2300w', 'min12xxw', 'c2050',
00669         'hpoj', 'pxljr', 'pnm2ppa', 'splix', 'hp-ppd', 'hpijs-ppds',
00670         'linuxprinting.org-ppds', 'openprinting-ppds',
00671         'openprinting-ppds-extra', 'ghostscript', 'cups',
00672         'cups-driver-gutenprint', 'foomatic-db-gutenprint', 'ijsgutenprint',
00673         'cupsys-driver-gutenprint', 'gimp-gutenprint', 'gutenprint-doc',
00674         'gutenprint-locales', 'system-config-printer-common', 'kdeprint')
00675 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_related_packages (   report,
  packages 
)
Attach version information for related packages

In the future, this might also run their hooks.

Definition at line 702 of file hookutils.py.

00702 
00703 def attach_related_packages(report, packages):
00704     '''Attach version information for related packages
00705 
00706     In the future, this might also run their hooks.
00707     '''
00708     report['RelatedPackageVersions'] = package_versions(*packages)
00709 

Here is the call graph for this function:

def apport.hookutils.attach_root_command_outputs (   report,
  command_map 
)
Execute multiple commands as root and put their outputs into report.

command_map is a keyname -> 'shell command' dictionary with the commands to
run. They are all run through /bin/sh, so you need to take care of shell
escaping yourself. To include stderr output of a command, end it with
"2>&1".

Just like root_command_output() this will use gksu, kdesudo, or sudo for
gaining root privileges, depending on the running desktop environment.

This is preferrable to using root_command_output() multiple times, as that
will ask for the password every time.

Definition at line 412 of file hookutils.py.

00412 
00413 def attach_root_command_outputs(report, command_map):
00414     '''Execute multiple commands as root and put their outputs into report.
00415 
00416     command_map is a keyname -> 'shell command' dictionary with the commands to
00417     run. They are all run through /bin/sh, so you need to take care of shell
00418     escaping yourself. To include stderr output of a command, end it with
00419     "2>&1".
00420 
00421     Just like root_command_output() this will use gksu, kdesudo, or sudo for
00422     gaining root privileges, depending on the running desktop environment.
00423 
00424     This is preferrable to using root_command_output() multiple times, as that
00425     will ask for the password every time.
00426     '''
00427     workdir = tempfile.mkdtemp()
00428     try:
00429         # create a shell script with all the commands
00430         script_path = os.path.join(workdir, ':script:')
00431         script = open(script_path, 'w')
00432         for keyname, command in command_map.items():
00433             assert hasattr(command, 'strip'), 'command must be a string (shell command)'
00434             # use "| cat" here, so that we can end commands with 2>&1
00435             # (otherwise it would have the wrong redirection order)
00436             script.write('%s | cat > %s\n' % (command, os.path.join(workdir, keyname)))
00437         script.close()
00438 
00439         # run script
00440         sp = subprocess.Popen(_root_command_prefix() + ['/bin/sh', script_path])
00441         sp.wait()
00442 
00443         # now read back the individual outputs
00444         for keyname in command_map:
00445             f = open(os.path.join(workdir, keyname))
00446             buf = f.read().strip()
00447             if buf:
00448                 report[keyname] = buf
00449             f.close()
00450     finally:
00451         shutil.rmtree(workdir)
00452 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_upstart_overrides (   report,
  package 
)
Attach information about any Upstart override files

Definition at line 151 of file hookutils.py.

00151 
00152 def attach_upstart_overrides(report, package):
00153     '''Attach information about any Upstart override files'''
00154 
00155     try:
00156         files = apport.packaging.get_files(package)
00157     except ValueError:
00158         return
00159 
00160     for file in files:
00161         if os.path.exists(file) and file.startswith('/etc/init/'):
00162             override = file.replace('.conf', '.override')
00163             key = 'upstart.' + override.replace('/etc/init/', '')
00164             attach_file_if_exists(report, override, key)
00165 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.attach_wifi (   report)
Attach wireless (WiFi) network information to report.

Definition at line 634 of file hookutils.py.

00634 
00635 def attach_wifi(report):
00636     '''Attach wireless (WiFi) network information to report.'''
00637 
00638     report['WifiSyslog'] = recent_syslog(re.compile(r'(NetworkManager|modem-manager|dhclient|kernel|wpa_supplicant)(\[\d+\])?:'))
00639     report['IwConfig'] = re.sub(
00640         'ESSID:(.*)', 'ESSID:<hidden>',
00641         re.sub('Encryption key:(.*)', 'Encryption key: <hidden>',
00642                re.sub('Access Point: (.*)', 'Access Point: <hidden>',
00643                       command_output(['iwconfig']))))
00644     report['RfKill'] = command_output(['rfkill', 'list'])
00645     report['CRDA'] = command_output(['iw', 'reg', 'get'])
00646 
00647     attach_file_if_exists(report, '/var/log/wpa_supplicant.log', key='WpaSupplicantLog')
00648 

Here is the call graph for this function:

Here is the caller graph for this function:

Is given command on the executable search path?

Definition at line 327 of file hookutils.py.

00327 
00328 def command_available(command):
00329     '''Is given command on the executable search path?'''
00330     if 'PATH' not in os.environ:
00331         return False
00332     path = os.environ['PATH']
00333     for element in path.split(os.pathsep):
00334         if not element:
00335             continue
00336         filename = os.path.join(element, command)
00337         if os.path.isfile(filename) and os.access(filename, os.X_OK):
00338             return True
00339     return False
00340 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.command_output (   command,
  input = None,
  stderr = subprocess.STDOUT,
  keep_locale = False,
  decode_utf8 = True 
)
Try to execute given command (array) and return its stdout.

In case of failure, a textual error gets returned. This function forces
LC_MESSAGES to C, to avoid translated output in bug reports.

If decode_utf8 is True (default), the output will be converted to a string,
otherwise left as bytes.

Definition at line 342 of file hookutils.py.

00342 
00343                    keep_locale=False, decode_utf8=True):
00344     '''Try to execute given command (array) and return its stdout.
00345 
00346     In case of failure, a textual error gets returned. This function forces
00347     LC_MESSAGES to C, to avoid translated output in bug reports.
00348 
00349     If decode_utf8 is True (default), the output will be converted to a string,
00350     otherwise left as bytes.
00351     '''
00352     env = os.environ.copy()
00353     if not keep_locale:
00354         env['LC_MESSAGES'] = 'C'
00355     try:
00356         sp = subprocess.Popen(command, stdout=subprocess.PIPE,
00357                               stderr=stderr,
00358                               stdin=(input and subprocess.PIPE or None),
00359                               env=env)
00360     except OSError as e:
00361         return 'Error: ' + str(e)
00362 
00363     out = sp.communicate(input)[0]
00364     if sp.returncode == 0:
00365         res = out.strip()
00366     else:
00367         res = (b'Error: command ' + str(command).encode() + b' failed with exit code '
00368                + str(sp.returncode).encode() + b': ' + out)
00369 
00370     if decode_utf8:
00371         res = res.decode('UTF-8', errors='replace')
00372     return res
00373 

Here is the caller graph for this function:

def apport.hookutils.files_in_package (   package,
  globpat = None 
)
Retrieve a list of files owned by package, optionally matching globpat

Definition at line 562 of file hookutils.py.

00562 
00563 def files_in_package(package, globpat=None):
00564     '''Retrieve a list of files owned by package, optionally matching globpat'''
00565 
00566     files = packaging.get_files(package)
00567     if globpat:
00568         result = [f for f in files if glob.fnmatch.fnmatch(f, globpat)]
00569     else:
00570         result = files
00571     return result
00572 

Here is the caller graph for this function:

Check if the problem happened in the currently running XDG session.

This can be used to determine if e. g. ~/.xsession-errors is relevant and
should be attached.

Return None if this cannot be determined due to not being able to talk to
ConsoleKit.

Definition at line 849 of file hookutils.py.

00849 
00850 def in_session_of_problem(report):
00851     '''Check if the problem happened in the currently running XDG session.
00852 
00853     This can be used to determine if e. g. ~/.xsession-errors is relevant and
00854     should be attached.
00855 
00856     Return None if this cannot be determined due to not being able to talk to
00857     ConsoleKit.
00858     '''
00859     # report time is in local TZ
00860     orig_ctime = locale.getlocale(locale.LC_TIME)
00861     try:
00862         locale.setlocale(locale.LC_TIME, 'C')
00863         report_time = time.mktime(time.strptime(report['Date']))
00864     except KeyError:
00865         return None
00866     finally:
00867         locale.setlocale(locale.LC_TIME, orig_ctime)
00868 
00869     try:
00870         bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
00871         ck_manager = Gio.DBusProxy.new_sync(
00872             bus, Gio.DBusProxyFlags.NONE, None,
00873             'org.freedesktop.ConsoleKit', '/org/freedesktop/ConsoleKit/Manager',
00874             'org.freedesktop.ConsoleKit.Manager', None)
00875 
00876         cur_session = ck_manager.GetCurrentSession()
00877 
00878         ck_session = Gio.DBusProxy.new_sync(
00879             bus, Gio.DBusProxyFlags.NONE, None,
00880             'org.freedesktop.ConsoleKit', cur_session,
00881             'org.freedesktop.ConsoleKit.Session', None)
00882 
00883         session_start_time = ck_session.GetCreationTime()
00884     except GLib.GError as e:
00885         sys.stderr.write('Error connecting to ConsoleKit: %s\n' % str(e))
00886         return None
00887 
00888     m = re.match('(\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d)(?:\.\d+Z)$', session_start_time)
00889     if m:
00890         # CK gives UTC time
00891         session_start_time = calendar.timegm(time.strptime(m.group(1), '%Y-%m-%dT%H:%M:%S'))
00892     else:
00893         sys.stderr.write('cannot parse time returned by CK: %s\n' % session_start_time)
00894         return None
00895 
00896     return session_start_time <= report_time
00897 

Here is the caller graph for this function:

def apport.hookutils.links_with_shared_library (   path,
  lib 
)
Returns True if the binary at path links with the library named lib.

path should be a fully qualified path (e.g. report['ExecutablePath'])
lib may be of the form 'lib<name>' or 'lib<name>.so.<version>'

Definition at line 759 of file hookutils.py.

00759 
00760 def links_with_shared_library(path, lib):
00761     '''Returns True if the binary at path links with the library named lib.
00762 
00763     path should be a fully qualified path (e.g. report['ExecutablePath'])
00764     lib may be of the form 'lib<name>' or 'lib<name>.so.<version>'
00765     '''
00766 
00767     libs = shared_libraries(path)
00768 
00769     if lib in libs:
00770         return True
00771 
00772     for linked_lib in libs:
00773         if linked_lib.startswith(lib + '.so.'):
00774             return True
00775 
00776     return False
00777 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.nonfree_kernel_modules (   module_list = '/proc/modules')
Check loaded modules and return a list of those which are not free.

Definition at line 799 of file hookutils.py.

00799 
00800 def nonfree_kernel_modules(module_list='/proc/modules'):
00801     '''Check loaded modules and return a list of those which are not free.'''
00802 
00803     try:
00804         with open(module_list) as f:
00805             mods = [l.split()[0] for l in f]
00806     except IOError:
00807         return []
00808 
00809     nonfree = []
00810     for m in mods:
00811         l = _get_module_license(m)
00812         if l and not ('GPL' in l or 'BSD' in l or 'MPL' in l or 'MIT' in l):
00813             nonfree.append(m)
00814 
00815     return nonfree
00816 

Here is the call graph for this function:

Here is the caller graph for this function:

Return a text listing of package names and versions.

Arguments may be package names or globs, e. g. "foo*"

Definition at line 710 of file hookutils.py.

00710 
00711 def package_versions(*packages):
00712     '''Return a text listing of package names and versions.
00713 
00714     Arguments may be package names or globs, e. g. "foo*"
00715     '''
00716     versions = []
00717     for package_pattern in packages:
00718         if not package_pattern:
00719             continue
00720 
00721         matching_packages = packaging.package_name_glob(package_pattern)
00722 
00723         if not matching_packages:
00724             versions.append((package_pattern, 'N/A'))
00725 
00726         for package in sorted(matching_packages):
00727             try:
00728                 version = packaging.get_version(package)
00729             except ValueError:
00730                 version = 'N/A'
00731             if version is None:
00732                 version = 'N/A'
00733             versions.append((package, version))
00734 
00735     package_width, version_width = \
00736         map(max, [map(len, t) for t in zip(*versions)])
00737 
00738     fmt = '%%-%ds %%s' % package_width
00739     return '\n'.join([fmt % v for v in versions])
00740 

Here is the caller graph for this function:

Generate a valid report key name from a file path.

This will replace invalid punctuation symbols with valid ones.

Definition at line 43 of file hookutils.py.

00043 
00044 def path_to_key(path):
00045     '''Generate a valid report key name from a file path.
00046 
00047     This will replace invalid punctuation symbols with valid ones.
00048     '''
00049     if sys.version[0] >= '3':
00050         if type(path) == type(b''):
00051             path = path.decode('UTF-8')
00052     else:
00053         if type(path) != type(b''):
00054             path = path.encode('UTF-8')
00055     return path.translate(_path_key_trans)
00056 

Here is the caller graph for this function:

def apport.hookutils.pci_devices (   pci_classes)
Return a text dump of PCI devices attached to the system.

Definition at line 522 of file hookutils.py.

00522 
00523 def pci_devices(*pci_classes):
00524     '''Return a text dump of PCI devices attached to the system.'''
00525 
00526     if not pci_classes:
00527         return command_output(['lspci', '-vvnn'])
00528 
00529     result = ''
00530     output = command_output(['lspci', '-vvmmnn'])
00531     for paragraph in output.split('\n\n'):
00532         pci_class = None
00533         slot = None
00534 
00535         for line in paragraph.split('\n'):
00536             try:
00537                 key, value = line.split(':', 1)
00538             except ValueError:
00539                 continue
00540             value = value.strip()
00541             key = key.strip()
00542             if key == 'Class':
00543                 n = int(value[-5:-1], 16)
00544                 pci_class = (n & 0xff00) >> 8
00545             elif key == 'Slot':
00546                 slot = value
00547 
00548         if pci_class and slot and pci_class in pci_classes:
00549             if result:
00550                 result += '\n\n'
00551             result += command_output(['lspci', '-vvnns', slot]).strip()
00552 
00553     return result
00554 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.read_file (   path,
  force_unicode = False 
)
Return the contents of the specified path.

If the contents is valid UTF-8, or force_unicode is True, then the value
will a string, otherwise it will be bytes.

Upon error, this will deliver a text representation of the error,
instead of failing.

Definition at line 76 of file hookutils.py.

00076 
00077 def read_file(path, force_unicode=False):
00078     '''Return the contents of the specified path.
00079 
00080     If the contents is valid UTF-8, or force_unicode is True, then the value
00081     will a string, otherwise it will be bytes.
00082 
00083     Upon error, this will deliver a text representation of the error,
00084     instead of failing.
00085     '''
00086     try:
00087         with open(path, 'rb') as f:
00088             contents = f.read().strip()
00089         if force_unicode:
00090             return contents.decode('UTF-8', errors='replace')
00091         try:
00092             return contents.decode('UTF-8')
00093         except UnicodeDecodeError:
00094             return contents
00095     except Exception as e:
00096         return 'Error: ' + str(e)
00097 

Here is the caller graph for this function:

def apport.hookutils.recent_logfile (   logfile,
  pattern,
  maxlines = 10000 
)
Extract recent messages from a logfile which match a regex.

pattern should be a "re" object. By default this catches at most the last
1000 lines, but this can be modified with a different maxlines argument.

Definition at line 461 of file hookutils.py.

00461 
00462 def recent_logfile(logfile, pattern, maxlines=10000):
00463     '''Extract recent messages from a logfile which match a regex.
00464 
00465     pattern should be a "re" object. By default this catches at most the last
00466     1000 lines, but this can be modified with a different maxlines argument.
00467     '''
00468     lines = ''
00469     try:
00470         tail = subprocess.Popen(['tail', '-n', str(maxlines), logfile],
00471                                 stdout=subprocess.PIPE)
00472         while tail.poll() is None:
00473             for line in tail.stdout:
00474                 line = line.decode('UTF-8', errors='replace')
00475                 if pattern.search(line):
00476                     lines += line
00477         tail.stdout.close()
00478         tail.wait()
00479     except IOError:
00480         return ''
00481     return lines
00482 

Here is the caller graph for this function:

def apport.hookutils.recent_syslog (   pattern)
Extract recent messages from syslog which match a regex.

pattern should be a "re" object.

Definition at line 453 of file hookutils.py.

00453 
00454 def recent_syslog(pattern):
00455     '''Extract recent messages from syslog which match a regex.
00456 
00457     pattern should be a "re" object.
00458     '''
00459     return recent_logfile('/var/log/syslog', pattern)
00460 

Here is the call graph for this function:

Here is the caller graph for this function:

def apport.hookutils.root_command_output (   command,
  input = None,
  stderr = subprocess.STDOUT,
  decode_utf8 = True 
)
Try to execute given command (array) as root and return its stdout.

This passes the command through gksu, kdesudo, or sudo, depending on the
running desktop environment.

In case of failure, a textual error gets returned.

If decode_utf8 is True (default), the output will be converted to a string,
otherwise left as bytes.

Definition at line 396 of file hookutils.py.

00396 
00397 def root_command_output(command, input=None, stderr=subprocess.STDOUT, decode_utf8=True):
00398     '''Try to execute given command (array) as root and return its stdout.
00399 
00400     This passes the command through gksu, kdesudo, or sudo, depending on the
00401     running desktop environment.
00402 
00403     In case of failure, a textual error gets returned.
00404 
00405     If decode_utf8 is True (default), the output will be converted to a string,
00406     otherwise left as bytes.
00407     '''
00408     assert isinstance(command, list), 'command must be a list'
00409     return command_output(_root_command_prefix() + command, input, stderr,
00410                           keep_locale=True, decode_utf8=decode_utf8)
00411 

Here is the call graph for this function:

Returns a list of strings containing the sonames of shared libraries
with which the specified binary is linked.

Definition at line 741 of file hookutils.py.

00741 
00742 def shared_libraries(path):
00743     '''Returns a list of strings containing the sonames of shared libraries
00744     with which the specified binary is linked.'''
00745 
00746     libs = set()
00747 
00748     for line in command_output(['ldd', path]).split('\n'):
00749         try:
00750             lib, rest = line.split('=>', 1)
00751         except ValueError:
00752             continue
00753 
00754         lib = lib.strip()
00755         libs.add(lib)
00756 
00757     return libs
00758 

Here is the call graph for this function:

Here is the caller graph for this function:

Return a text dump of USB devices attached to the system.

Definition at line 555 of file hookutils.py.

00555 
00556 def usb_devices():
00557     '''Return a text dump of USB devices attached to the system.'''
00558 
00559     # TODO: would be nice to be able to filter by interface class
00560     return command_output(['lsusb', '-v'])
00561 

Here is the call graph for this function:

def apport.hookutils.xsession_errors (   pattern = None)
Extract messages from ~/.xsession-errors.

By default this parses out glib-style warnings, errors, criticals etc. and
X window errors.  You can specify a "re" object as pattern to customize the
filtering.

Please note that you should avoid attaching the whole file to reports, as
it can, and often does, contain sensitive and private data.

Definition at line 483 of file hookutils.py.

00483 
00484 def xsession_errors(pattern=None):
00485     '''Extract messages from ~/.xsession-errors.
00486 
00487     By default this parses out glib-style warnings, errors, criticals etc. and
00488     X window errors.  You can specify a "re" object as pattern to customize the
00489     filtering.
00490 
00491     Please note that you should avoid attaching the whole file to reports, as
00492     it can, and often does, contain sensitive and private data.
00493     '''
00494     path = os.path.expanduser('~/.xsession-errors')
00495     if not os.path.exists(path):
00496         return ''
00497 
00498     if not pattern:
00499         pattern = re.compile('^(\(.*:\d+\): \w+-(WARNING|CRITICAL|ERROR))|(Error: .*No Symbols named)|([^ ]+\[\d+\]: ([A-Z]+):)|([^ ]-[A-Z]+ \*\*:)|(received an X Window System error)|(^The error was \')|(^  \(Details: serial \d+ error_code)')
00500 
00501     lines = ''
00502     with open(path, 'rb') as f:
00503         for line in f:
00504             line = line.decode('UTF-8', errors='replace')
00505             if pattern.search(line):
00506                 lines += line
00507     return lines

Here is the caller graph for this function:


Variable Documentation

Definition at line 36 of file hookutils.py.

Definition at line 515 of file hookutils.py.

Definition at line 513 of file hookutils.py.

Definition at line 510 of file hookutils.py.

Definition at line 517 of file hookutils.py.

Definition at line 516 of file hookutils.py.

Definition at line 508 of file hookutils.py.

Definition at line 512 of file hookutils.py.

Definition at line 511 of file hookutils.py.

Definition at line 509 of file hookutils.py.

Definition at line 518 of file hookutils.py.

Definition at line 519 of file hookutils.py.

Definition at line 514 of file hookutils.py.