home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / apport / hookutils.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-10-12  |  15.3 KB  |  470 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''Convenience functions for use in package hooks.
  5.  
  6. Copyright (C) 2008-2009 Canonical Ltd.
  7. Author: Matt Zimmerman <mdz@canonical.com>
  8. Contributor: Brian Murray <brian@ubuntu.com>
  9.  
  10. This program is free software; you can redistribute it and/or modify it
  11. under the terms of the GNU General Public License as published by the
  12. Free Software Foundation; either version 2 of the License, or (at your
  13. option) any later version.  See http://www.gnu.org/copyleft/gpl.html for
  14. the full text of the license.
  15. '''
  16. import subprocess
  17. import hashlib
  18. import os
  19. import datetime
  20. import glob
  21. import re
  22. import string
  23. import xml.dom as xml
  24. import xml.dom.minidom as xml
  25. from packaging_impl import impl as packaging
  26. _path_key_trans = string.maketrans('#/-_+', '.....')
  27.  
  28. def path_to_key(path):
  29.     """Generate a valid report key name from a file path.
  30.         
  31.     This will meet apport's restrictions on the characters used in keys.
  32.     """
  33.     return path.translate(_path_key_trans)
  34.  
  35.  
  36. def attach_file_if_exists(report, path, key = None):
  37.     '''Attach file contents if file exists.'''
  38.     if not key:
  39.         key = path_to_key(path)
  40.     
  41.     if os.path.exists(path):
  42.         attach_file(report, path, key)
  43.     
  44.  
  45.  
  46. def read_file(path):
  47.     '''Return the contents of the specified path. 
  48.         
  49.     Upon error, this will deliver a a text representation of the error,
  50.     instead of failing.
  51.     '''
  52.     
  53.     try:
  54.         return open(path).read().strip()
  55.     except Exception:
  56.         e = None
  57.         return 'Error: ' + str(e)
  58.  
  59.  
  60.  
  61. def attach_file(report, path, key = None):
  62.     '''Attach a file to the report.
  63.  
  64.     If key is not specified, the key name will be derived from the file
  65.     name with path_to_key().
  66.     '''
  67.     if not key:
  68.         key = path_to_key(path)
  69.     
  70.     report[key] = read_file(path)
  71.  
  72.  
  73. def attach_conffiles(report, package, conffiles = None):
  74.     '''Attach information about any modified or deleted conffiles'''
  75.     output = command_output([
  76.         'dpkg-query',
  77.         '-W',
  78.         '--showformat=${Conffiles}',
  79.         package])
  80.     for line in output.split('\n'):
  81.         (path, default_md5sum) = line.strip().split()
  82.         if conffiles and path not in conffiles:
  83.             continue
  84.         
  85.         key = 'modified.conffile.' + path_to_key(path)
  86.         if os.path.exists(path):
  87.             contents = open(path).read()
  88.             m = hashlib.md5()
  89.             m.update(contents)
  90.             calculated_md5sum = m.hexdigest()
  91.             if calculated_md5sum != default_md5sum:
  92.                 report[key] = contents
  93.                 statinfo = os.stat(path)
  94.                 mtime = datetime.datetime.fromtimestamp(statinfo.st_mtime)
  95.                 mtime_key = 'mtime.conffile.' + path_to_key(path)
  96.                 report[mtime_key] = mtime.isoformat()
  97.             
  98.         calculated_md5sum != default_md5sum
  99.         report[key] = '[deleted]'
  100.     
  101.  
  102.  
  103. def attach_dmesg(report):
  104.     '''Attach information from the kernel ring buffer (dmesg).'''
  105.     report['BootDmesg'] = open('/var/log/dmesg').read()
  106.     report['CurrentDmesg'] = command_output([
  107.         'sh',
  108.         '-c',
  109.         'dmesg | comm -13 /var/log/dmesg -'])
  110.  
  111.  
  112. def attach_machinetype(report):
  113.     '''Calculate and attach a specific machine type if possible.'''
  114.     if 'HalComputerInfo' in report:
  115.         system = ''
  116.         vendor = re.compile("system.hardware.vendor\\s*=\\s*'(.*)'\\s*\\(string\\)")
  117.         match = vendor.search(report['HalComputerInfo'])
  118.         if match:
  119.             system += match.group(1).rstrip() + ' '
  120.         
  121.         product = re.compile("system.hardware.product\\s*=\\s*'(.*)'\\s*\\(string\\)")
  122.         match = product.search(report['HalComputerInfo'])
  123.         if match:
  124.             system += match.group(1).rstrip() + ' '
  125.         
  126.         if system != '':
  127.             report['MachineType'] = system.rstrip()
  128.         
  129.     
  130.  
  131.  
  132. def attach_hardware(report):
  133.     attach_dmesg(report)
  134.     attach_file(report, '/proc/interrupts', 'ProcInterrupts')
  135.     attach_file(report, '/proc/version_signature', 'ProcVersionSignature')
  136.     attach_file(report, '/proc/cpuinfo', 'ProcCpuinfo')
  137.     attach_file(report, '/proc/cmdline', 'ProcCmdLine')
  138.     attach_file(report, '/proc/modules', 'ProcModules')
  139.     report['Lspci'] = command_output([
  140.         'lspci',
  141.         '-vvnn'])
  142.     report['Lsusb'] = command_output([
  143.         'lsusb'])
  144.     report['HalComputerInfo'] = hal_dump_udi('/org/freedesktop/Hal/devices/computer')
  145.     if 'Uname' in report:
  146.         del report['Uname']
  147.     
  148.     attach_machinetype(report)
  149.  
  150.  
  151. def attach_alsa(report):
  152.     '''Attach ALSA subsystem information to the report.
  153.  
  154.     (loosely based on http://www.alsa-project.org/alsa-info.sh)
  155.         '''
  156.     attach_file_if_exists(report, os.path.expanduser('~/.asoundrc'), 'UserAsoundrc')
  157.     attach_file_if_exists(report, os.path.expanduser('~/.asoundrc.asoundconf'), 'UserAsoundrcAsoundconf')
  158.     attach_file_if_exists(report, '/etc/asound.conf')
  159.     report['AlsaDevices'] = command_output([
  160.         'ls',
  161.         '-l',
  162.         '/dev/snd/'])
  163.     report['AplayDevices'] = command_output([
  164.         'aplay',
  165.         '-l'])
  166.     report['ArecordDevices'] = command_output([
  167.         'arecord',
  168.         '-l'])
  169.     report['PciMultimedia'] = pci_devices(PCI_MULTIMEDIA)
  170.     cards = []
  171.     for line in open('/proc/asound/cards'):
  172.         if ']:' in line:
  173.             fields = line.lstrip().split()
  174.             cards.append(int(fields[0]))
  175.             continue
  176.     
  177.     for card in cards:
  178.         key = 'Card%d.Amixer.info' % card
  179.         report[key] = command_output([
  180.             'amixer',
  181.             '-c',
  182.             str(card),
  183.             'info'])
  184.         key = 'Card%d.Amixer.values' % card
  185.         report[key] = command_output([
  186.             'amixer',
  187.             '-c',
  188.             str(card)])
  189.         for codecpath in glob.glob('/proc/asound/card%d/codec*' % card):
  190.             if os.path.isfile(codecpath):
  191.                 codec = os.path.basename(codecpath)
  192.                 key = 'Card%d.Codecs.%s' % (card, path_to_key(codec))
  193.                 attach_file(report, codecpath, key = key)
  194.                 continue
  195.             if os.path.isdir(codecpath):
  196.                 codec = os.path.basename(codecpath)
  197.                 for name in os.listdir(codecpath):
  198.                     path = os.path.join(codecpath, name)
  199.                     key = 'Card%d.Codecs.%s.%s' % (card, path_to_key(codec), path_to_key(name))
  200.                     attach_file(report, path, key)
  201.                 
  202.         
  203.     
  204.     report['AudioDevicesInUse'] = command_output([
  205.         'fuser',
  206.         '-v'] + glob.glob('/dev/dsp*') + glob.glob('/dev/snd/*') + glob.glob('/dev/seq*'))
  207.     attach_dmesg(report)
  208.  
  209.  
  210. def command_output(command, input = None, stderr = subprocess.STDOUT):
  211.     '''Try to execute given command (array) and return its stdout. 
  212.     
  213.     In case of failure, a textual error gets returned.
  214.     '''
  215.     
  216.     try:
  217.         sp = subprocess.Popen(command, stdout = subprocess.PIPE, stderr = stderr, close_fds = True)
  218.     except OSError:
  219.         e = None
  220.         return 'Error: ' + str(e)
  221.  
  222.     out = sp.communicate(input)[0]
  223.     if sp.returncode == 0:
  224.         return out.strip()
  225.     return 'Error: command %s failed with exit code %i: %s' % (str(command), sp.returncode, out)
  226.  
  227.  
  228. def recent_syslog(pattern):
  229.     '''Extract recent messages from syslog which match a regex.
  230.         
  231.     pattern should be a "re" object.
  232.     '''
  233.     lines = ''
  234.     for line in open('/var/log/syslog'):
  235.         if pattern.search(line):
  236.             lines += line
  237.             continue
  238.     
  239.     return lines
  240.  
  241. PCI_MASS_STORAGE = 1
  242. PCI_NETWORK = 2
  243. PCI_DISPLAY = 3
  244. PCI_MULTIMEDIA = 4
  245. PCI_MEMORY = 5
  246. PCI_BRIDGE = 6
  247. PCI_SIMPLE_COMMUNICATIONS = 7
  248. PCI_BASE_SYSTEM_PERIPHERALS = 8
  249. PCI_INPUT_DEVICES = 9
  250. PCI_DOCKING_STATIONS = 10
  251. PCI_PROCESSORS = 11
  252. PCI_SERIAL_BUS = 12
  253.  
  254. def pci_devices(*pci_classes):
  255.     '''Return a text dump of PCI devices attached to the system.'''
  256.     if not pci_classes:
  257.         return command_output([
  258.             'lspci',
  259.             '-vvnn'])
  260.     slots = []
  261.     output = command_output([
  262.         'lspci',
  263.         '-vvmmnn'])
  264.     for paragraph in output.split('\n\n'):
  265.         pci_class = None
  266.         pci_subclass = None
  267.         slot = None
  268.         for line in paragraph.split('\n'):
  269.             (key, value) = line.split(':', 1)
  270.             value = value.strip()
  271.             key = key.strip()
  272.             if key == 'Class':
  273.                 n = int(value[-5:-1], 16)
  274.                 pci_class = (n & 65280) >> 8
  275.                 pci_subclass = n & 255
  276.                 continue
  277.             pci_classes
  278.             if key == 'Slot':
  279.                 slot = value
  280.                 continue
  281.         
  282.         if pci_class and slot and pci_class in pci_classes:
  283.             slots.append(slot)
  284.             continue
  285.     
  286.     cmd = [
  287.         'lspci',
  288.         '-vvnn']
  289.     for slot in slots:
  290.         cmd.extend([
  291.             '-s',
  292.             slot])
  293.     
  294.     return command_output(cmd)
  295.  
  296.  
  297. def usb_devices():
  298.     '''Return a text dump of USB devices attached to the system.'''
  299.     return command_output([
  300.         'lsusb',
  301.         '-v'])
  302.  
  303.  
  304. def hal_find_by_capability(capability):
  305.     '''Retrieve a list of UDIs for hal objects having the specified capability.'''
  306.     output = command_output([
  307.         'hal-find-by-capability',
  308.         '--capability',
  309.         capability])
  310.     return output.split('\n')
  311.  
  312.  
  313. def hal_dump_udi(udi):
  314.     '''Dump the properties of a HAL object, specified by its UDI.'''
  315.     out = command_output([
  316.         'lshal',
  317.         '-u',
  318.         udi])
  319.     result = ''
  320.     for l in out.splitlines():
  321.         if '.serial =' in l:
  322.             continue
  323.         
  324.         result += l + '\n'
  325.     
  326.     return result
  327.  
  328.  
  329. def files_in_package(package, globpat = None):
  330.     '''Retrieve a list of files owned by package, optionally matching globpat'''
  331.     files = packaging.get_files(package)
  332.     return result
  333.  
  334.  
  335. def attach_gconf(report, package):
  336.     '''Attach information about gconf keys set to non-default values.'''
  337.     import gconf
  338.     import glib
  339.     client = gconf.client_get_default()
  340.     non_defaults = { }
  341.     for schema_file in files_in_package(package, '/usr/share/gconf/schemas/*.schemas'):
  342.         for key, default_value in _parse_gconf_schema(schema_file).items():
  343.             
  344.             try:
  345.                 value = client.get(key).to_string()
  346.                 if value != default_value:
  347.                     non_defaults[key] = value
  348.             continue
  349.             except glib.GError:
  350.                 value = command_output([
  351.                     'gconftool-2',
  352.                     '-g',
  353.                     key])
  354.                 if value != default_value:
  355.                     non_defaults[key] = value
  356.                 
  357.                 value != default_value
  358.             
  359.  
  360.         
  361.     
  362.     if non_defaults:
  363.         s = ''
  364.         keys = non_defaults.keys()
  365.         keys.sort()
  366.         for key in keys:
  367.             value = non_defaults[key]
  368.             s += '%s=%s\n' % (key, value)
  369.         
  370.         report['GConfNonDefault'] = s
  371.     
  372.  
  373.  
  374. def attach_network(report):
  375.     '''Attach network-related information to report.'''
  376.     report['IpRoute'] = command_output([
  377.         'ip',
  378.         'route'])
  379.     report['IpAddr'] = command_output([
  380.         'ip',
  381.         'addr'])
  382.     report['PciNetwork'] = pci_devices(PCI_NETWORK)
  383.     for var in ('http_proxy', 'ftp_proxy', 'no_proxy'):
  384.         if var in os.environ:
  385.             report[var] = os.environ[var]
  386.             continue
  387.     
  388.  
  389.  
  390. def attach_printing(report):
  391.     '''Attach printing information to the report.
  392.  
  393.     Based on http://wiki.ubuntu.com/PrintingBugInfoScript.
  394.     '''
  395.     attach_file_if_exists(report, '/etc/papersize', 'Papersize')
  396.     attach_file_if_exists(report, '/var/log/cups/error_log', 'CupsErrorLog')
  397.     report['Locale'] = command_output([
  398.         'locale'])
  399.     report['Lpstat'] = command_output([
  400.         'lpstat',
  401.         '-v'])
  402.     ppds = glob.glob('/etc/cups/ppd/*.ppd')
  403.     if ppds:
  404.         nicknames = command_output([
  405.             'fgrep',
  406.             '-H',
  407.             '*NickName'] + ppds)
  408.         report['PpdFiles'] = re.sub('/etc/cups/ppd/(.*).ppd:\\*NickName: *"(.*)"', '\\g<1>: \\g<2>', nicknames)
  409.     
  410.     report['PrintingPackages'] = package_versions('foo2zjs', 'foomatic-db', 'foomatic-db-engine', 'foomatic-db-gutenprint', 'foomatic-db-hpijs', 'foomatic-filters', 'foomatic-gui', 'hpijs', 'hplip', 'm2300w', 'min12xxw', 'c2050', 'hpoj', 'pxljr', 'pnm2ppa', 'splix', 'hp-ppd', 'hpijs-ppds', 'linuxprinting.org-ppds', 'openprinting-ppds', 'openprinting-ppds-extra', 'ghostscript', 'cups', 'cups-driver-gutenprint', 'foomatic-db-gutenprint', 'ijsgutenprint', 'cupsys-driver-gutenprint', 'gimp-gutenprint', 'gutenprint-doc', 'gutenprint-locales', 'system-config-printer-common', 'kdeprint')
  411.  
  412.  
  413. def attach_related_packages(report, packages):
  414.     '''Attach version information for related packages
  415.  
  416.        In the future, this might also run their hooks.'''
  417.     report['RelatedPackageVersions'] = package_versions(*packages)
  418.  
  419.  
  420. def package_versions(*packages):
  421.     '''Return a text listing of package names and versions for the specified
  422.     packages.  Arguments may be package names or glob patterns, e.g. "foo*"'''
  423.     versions = ''
  424.     for package_pattern in packages:
  425.         for package in package_glob(package_pattern):
  426.             
  427.             try:
  428.                 version = packaging.get_version(package)
  429.             except ValueError:
  430.                 version = 'N/A'
  431.  
  432.             if version is None:
  433.                 version = 'N/A'
  434.             
  435.             versions += '%s %s\n' % (package, version)
  436.         
  437.     
  438.     return versions
  439.  
  440.  
  441. def package_glob(name):
  442.     '''Return a list of known packages matching name'''
  443.     all_packages = command_output([
  444.         'apt-cache',
  445.         'pkgnames']).split('\n')
  446.     return glob.fnmatch.filter(all_packages, name)
  447.  
  448.  
  449. def _parse_gconf_schema(schema_file):
  450.     ret = { }
  451.     dom = xml.dom.minidom.parse(schema_file)
  452.     for gconfschemafile in dom.getElementsByTagName('gconfschemafile'):
  453.         for schemalist in gconfschemafile.getElementsByTagName('schemalist'):
  454.             for schema in schemalist.getElementsByTagName('schema'):
  455.                 key = schema.getElementsByTagName('applyto')[0].childNodes[0].data
  456.                 type = schema.getElementsByTagName('type')[0].childNodes[0].data
  457.                 default = schema.getElementsByTagName('default')[0].childNodes[0].data
  458.                 if type == 'bool':
  459.                     if default:
  460.                         ret[key] = 'true'
  461.                     else:
  462.                         ret[key] = 'false'
  463.                 default
  464.                 ret[key] = default
  465.             
  466.         
  467.     
  468.     return ret
  469.  
  470.