home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / lib / python2.6 / dist-packages / jockey / oslib.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2009-04-20  |  20.1 KB  |  635 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. '''Encapsulate operations which are Linux distribution specific.'''
  5. import fcntl
  6. import os
  7. import subprocess
  8. import sys
  9. import logging
  10. import re
  11. import tempfile
  12. from glob import glob
  13. import warnings
  14. warnings.simplefilter('ignore', FutureWarning)
  15. import apt
  16.  
  17. class _CapturedInstallProgress(apt.InstallProgress):
  18.     
  19.     def fork(self):
  20.         '''Reroute stdout/stderr to files, so that we can log them'''
  21.         self.stdout = tempfile.TemporaryFile()
  22.         self.stderr = tempfile.TemporaryFile()
  23.         p = os.fork()
  24.         if p == 0:
  25.             os.dup2(self.stdout.fileno(), sys.stdout.fileno())
  26.             os.dup2(self.stderr.fileno(), sys.stderr.fileno())
  27.         
  28.         return p
  29.  
  30.  
  31.  
  32. class OSLib:
  33.     '''Encapsulation of operating system/Linux distribution specific operations.'''
  34.     inst = None
  35.     
  36.     def __init__(self, client_only = False):
  37.         '''Set default paths and load the module blacklist.
  38.         
  39.         Distributors might want to override some default paths.
  40.         If client_only is True, this only initializes functionality which is
  41.         needed by clients, and which can be done without special privileges.
  42.         '''
  43.         self._get_os_version()
  44.         self.hal_get_property_path = '/usr/bin/hal-get-property'
  45.         if client_only:
  46.             return None
  47.         self.sys_dir = '/sys'
  48.         self.module_blacklist_file = '/etc/modprobe.d/blacklist-local.conf'
  49.         self.modinfo_path = '/sbin/modinfo'
  50.         self.modprobe_path = '/sbin/modprobe'
  51.         self.proc_modules = '/proc/modules'
  52.         self.handler_dir = '/usr/share/jockey/handlers'
  53.         self.modaliases = [
  54.             '/lib/modules/%s/modules.alias' % os.uname()[2],
  55.             '/usr/share/jockey/modaliases/']
  56.         self.xorg_conf_path = '/etc/X11/xorg.conf'
  57.         self.set_backup_dir()
  58.         self.check_cache = os.path.join(self.backup_dir, 'check')
  59.         self._load_module_blacklist()
  60.         self.apt_show_cache = { }
  61.         self.apt_sources = '/etc/apt/sources.list'
  62.         self.apt_jockey_source = '/etc/apt/sources.list.d/jockey.list'
  63.  
  64.     
  65.     def _apt_show(self, package):
  66.         '''Return apt-cache show output, with caching.
  67.         
  68.         Return None if the package does not exist.
  69.         '''
  70.         
  71.         try:
  72.             return self.apt_show_cache[package]
  73.         except KeyError:
  74.             apt = subprocess.Popen([
  75.                 'apt-cache',
  76.                 'show',
  77.                 package], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  78.             out = apt.communicate()[0].strip()
  79.             if apt.returncode == 0 and out:
  80.                 result = out
  81.             else:
  82.                 result = None
  83.             self.apt_show_cache[package] = result
  84.             return result
  85.  
  86.  
  87.     
  88.     def is_package_free(self, package):
  89.         '''Return if given package is free software.'''
  90.         out = self._apt_show(package)
  91.         if out:
  92.             for l in out.splitlines():
  93.                 if l.startswith('Section:'):
  94.                     s = l.split()[-1]
  95.                     if not s.startswith('restricted'):
  96.                         pass
  97.                     return not s.startswith('multiverse')
  98.             
  99.         
  100.         raise ValueError, 'package %s does not exist' % package
  101.  
  102.     
  103.     def package_installed(self, package):
  104.         '''Return if the given package is installed.'''
  105.         dpkg = subprocess.Popen([
  106.             'dpkg-query',
  107.             '-W',
  108.             '-f${Status}',
  109.             package], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  110.         out = dpkg.communicate()[0]
  111.         if dpkg.returncode == 0:
  112.             pass
  113.         return out.split()[-1] == 'installed'
  114.  
  115.     
  116.     def package_description(self, package):
  117.         '''Return a tuple (short_description, long_description) for a package.
  118.         
  119.         This should raise a ValueError if the package is not available.
  120.         '''
  121.         out = self._apt_show(package)
  122.         if out:
  123.             lines = out.splitlines()
  124.             start = 0
  125.             while start < len(lines) - 1:
  126.                 if lines[start].startswith('Description:'):
  127.                     break
  128.                 
  129.                 start += 1
  130.             short = lines[start].split(' ', 1)[1]
  131.             long = ''
  132.             for l in lines[start + 1:]:
  133.                 if l == ' .':
  134.                     long += '\n\n'
  135.                     continue
  136.                 if l.startswith(' '):
  137.                     long += l.lstrip()
  138.                     continue
  139.             
  140.             return (short, long)
  141.         raise ValueError, 'package %s does not exist' % package
  142.  
  143.     
  144.     def package_files(self, package):
  145.         '''Return a list of files shipped by a package.
  146.         
  147.         This should raise a ValueError if the package is not installed.
  148.         '''
  149.         pkcon = subprocess.Popen([
  150.             'dpkg',
  151.             '-L',
  152.             package], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  153.         out = pkcon.communicate()[0]
  154.         if pkcon.returncode == 0:
  155.             return out.splitlines()
  156.         raise ValueError, 'package %s is not installed' % package
  157.  
  158.     
  159.     def install_package(self, package, progress_cb):
  160.         """Install the given package.
  161.  
  162.         As this is called in the backend, this must happen noninteractively.
  163.         For progress reporting, progress_cb(phase, current, total) is called
  164.         regularly, with 'phase' being 'download' or 'install'. If the callback
  165.         returns True, the installation is attempted to get cancelled (this
  166.         will probably succeed in the 'download' phase, but not in 'install').
  167.         Passes '-1' for current and/or total if time cannot be determined.
  168.  
  169.         If this succeeds, subsequent package_installed(package) calls must
  170.         return True.
  171.  
  172.         Any installation failure should be raised as a SystemError.
  173.         """
  174.         
  175.         class MyFetchProgress(apt.FetchProgress):
  176.             
  177.             def __init__(self, callback):
  178.                 apt.FetchProgress.__init__(self)
  179.                 self.callback = callback
  180.  
  181.             
  182.             def pulse(self):
  183.                 return not self.callback('download', int(self.percent / 2 + 0.5), 100)
  184.  
  185.  
  186.         
  187.         class MyInstallProgress(_CapturedInstallProgress):
  188.             
  189.             def __init__(self, callback):
  190.                 _CapturedInstallProgress.__init__(self)
  191.                 self.callback = callback
  192.  
  193.             
  194.             def statusChange(self, pkg, percent, status):
  195.                 logging.debug('install progress statusChange %s %f' % (pkg, percent))
  196.                 self.callback('install', int(percent / 2 + 50.5), 100)
  197.  
  198.  
  199.         logging.debug('Installing package: %s', package)
  200.         if progress_cb:
  201.             progress_cb('download', 0, 100)
  202.         
  203.         os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
  204.         os.environ['PATH'] = '/sbin:/usr/sbin:/bin:/usr/bin'
  205.         apt.apt_pkg.Config.Set('DPkg::options::', '--force-confnew')
  206.         c = apt.Cache()
  207.         
  208.         try:
  209.             
  210.             try:
  211.                 c[package].markInstall()
  212.             except KeyError:
  213.                 logging.debug('Package %s does not exist, aborting', package)
  214.                 return False
  215.  
  216.             if not progress_cb or MyInstallProgress(progress_cb):
  217.                 pass
  218.             inst_p = None
  219.             if not progress_cb or MyFetchProgress(progress_cb):
  220.                 pass
  221.             c.commit(None, inst_p)
  222.             if inst_p:
  223.                 inst_p.stdout.seek(0)
  224.                 out = inst_p.stdout.read()
  225.                 inst_p.stdout.close()
  226.                 inst_p.stderr.seek(0)
  227.                 err = inst_p.stderr.read()
  228.                 inst_p.stderr.close()
  229.                 if out:
  230.                     logging.debug(out)
  231.                 
  232.                 if err:
  233.                     logging.error(err)
  234.                 
  235.         except apt.cache.FetchCancelledException:
  236.             e = None
  237.             return False
  238.             except (apt.cache.LockFailedException, apt.cache.FetchFailedException):
  239.                 e = None
  240.                 logging.warning('Package fetching failed: %s', str(e))
  241.                 raise SystemError, str(e)
  242.             except:
  243.                 None<EXCEPTION MATCH>(apt.cache.LockFailedException, apt.cache.FetchFailedException)
  244.             
  245.  
  246.         return True
  247.  
  248.     
  249.     def remove_package(self, package, progress_cb):
  250.         """Uninstall the given package.
  251.  
  252.         As this is called in the backend, this must happen noninteractively.
  253.         For progress reporting, progress_cb(current, total) is called
  254.         regularly. Passes '-1' for current and/or total if time cannot be
  255.         determined.
  256.  
  257.         If this succeeds, subsequent package_installed(package) calls must
  258.         return False.
  259.  
  260.         Any removal failure should be raised as a SystemError.
  261.         """
  262.         os.environ['DEBIAN_FRONTEND'] = 'noninteractive'
  263.         os.environ['PATH'] = '/sbin:/usr/sbin:/bin:/usr/bin'
  264.         
  265.         class MyInstallProgress(_CapturedInstallProgress):
  266.             
  267.             def __init__(self, callback):
  268.                 _CapturedInstallProgress.__init__(self)
  269.                 self.callback = callback
  270.  
  271.             
  272.             def statusChange(self, pkg, percent, status):
  273.                 logging.debug('remove progress statusChange %s %f' % (pkg, percent))
  274.                 self.callback(percent, 100)
  275.  
  276.  
  277.         logging.debug('Removing package: %s', package)
  278.         c = apt.Cache()
  279.         
  280.         try:
  281.             
  282.             try:
  283.                 c[package].markDelete()
  284.             except KeyError:
  285.                 logging.debug('Package %s does not exist, aborting', package)
  286.                 return False
  287.  
  288.             if not progress_cb or MyInstallProgress(progress_cb):
  289.                 pass
  290.             inst_p = None
  291.             c.commit(None, inst_p)
  292.             if inst_p:
  293.                 inst_p.stdout.seek(0)
  294.                 out = inst_p.stdout.read()
  295.                 inst_p.stdout.close()
  296.                 inst_p.stderr.seek(0)
  297.                 err = inst_p.stderr.read()
  298.                 inst_p.stderr.close()
  299.                 if out:
  300.                     logging.debug(out)
  301.                 
  302.                 if err:
  303.                     logging.error(err)
  304.                 
  305.         except apt.cache.LockFailedException:
  306.             e = None
  307.             logging.debug('could not lock apt cache, aborting: %s', str(e))
  308.             raise SystemError, str(e)
  309.  
  310.         return True
  311.  
  312.     
  313.     def packaging_system(self):
  314.         '''Return packaging system.
  315.  
  316.         Currently defined values: apt
  317.         '''
  318.         if os.path.exists('/etc/apt/sources.list') or os.path.exists('/etc/apt/sources.list.d'):
  319.             return 'apt'
  320.         raise NotImplementedError, 'local packaging system is unknown'
  321.  
  322.     
  323.     def add_repository(self, repository):
  324.         '''Add a repository.
  325.  
  326.         The format for repository is distribution specific. This function
  327.         should also download/update the package index for this repository.
  328.  
  329.         This should throw a ValueError if the repository is invalid or
  330.         inaccessible.
  331.         '''
  332.         if self.repository_enabled(repository):
  333.             logging.debug('add_repository(%s): already active', repository)
  334.             return None
  335.         if os.path.exists(self.apt_jockey_source):
  336.             backup = self.apt_jockey_source + '.bak'
  337.             os.rename(self.apt_jockey_source, backup)
  338.         else:
  339.             backup = None
  340.         f = open(self.apt_jockey_source, 'w')
  341.         print >>f, repository.strip()
  342.         f.close()
  343.         
  344.         try:
  345.             c = apt.Cache()
  346.             c.update()
  347.         except SystemError:
  348.             e = None
  349.             logging.error('add_repository(%s): Invalid repository', repository)
  350.             if backup:
  351.                 os.rename(backup, self.apt_jockey_source)
  352.             else:
  353.                 os.unlink(self.apt_jockey_source)
  354.             raise ValueError(e.message)
  355.         except apt.cache.FetchCancelledException:
  356.             e = None
  357.             return False
  358.             except (apt.cache.LockFailedException, apt.cache.FetchFailedException):
  359.                 e = None
  360.                 logging.warning('Package fetching failed: %s', str(e))
  361.                 raise SystemError, str(e)
  362.             except:
  363.                 None<EXCEPTION MATCH>(apt.cache.LockFailedException, apt.cache.FetchFailedException)
  364.             
  365.  
  366.  
  367.     
  368.     def remove_repository(self, repository):
  369.         '''Remove a repository.
  370.  
  371.         The format for repository is distribution specific.
  372.         '''
  373.         if not os.path.exists(self.apt_jockey_source):
  374.             return None
  375.         result = []
  376.         for line in open(self.apt_jockey_source):
  377.             if line.strip() != repository:
  378.                 result.append(line)
  379.                 continue
  380.             os.path.exists(self.apt_jockey_source)
  381.         
  382.         if result:
  383.             f = open(self.apt_jockey_source, 'w')
  384.             f.write('\n'.join(result))
  385.             f.close()
  386.         else:
  387.             os.unlink(self.apt_jockey_source)
  388.  
  389.     
  390.     def repository_enabled(self, repository):
  391.         '''Check if given repository is enabled.'''
  392.         for f in [
  393.             self.apt_sources] + glob(self.apt_sources + '.d/*.list'):
  394.             
  395.             try:
  396.                 logging.debug('repository_enabled(%s): checking %s', repository, f)
  397.                 for line in open(f):
  398.                     if line.strip() == repository:
  399.                         logging.debug('repository_enabled(%s): match', repository)
  400.                         return True
  401.             continue
  402.             except IOError:
  403.                 continue
  404.             
  405.  
  406.         
  407.         logging.debug('repository_enabled(%s): no match', repository)
  408.         return False
  409.  
  410.     
  411.     def ui_help_available(self, ui):
  412.         '''Return if help is available.
  413.  
  414.         This gets the current UI object passed, which can be used to determine
  415.         whether GTK/KDE is used, etc.
  416.         '''
  417.         return os.access('/usr/bin/yelp', os.X_OK)
  418.  
  419.     
  420.     def ui_help(self, ui):
  421.         """The UI's help button was clicked.
  422.  
  423.         This should open a help HTML page or website, call yelp with an
  424.         appropriate topic, etc. This gets the current UI object passed, which
  425.         can be used to determine whether GTK/KDE is used, etc.
  426.         """
  427.         if 'gtk' in str(ui.__class__).lower():
  428.             import gobject
  429.             gobject.spawn_async([
  430.                 'yelp',
  431.                 'ghelp:hardware#restricted-manager'], flags = gobject.SPAWN_SEARCH_PATH)
  432.         
  433.  
  434.     
  435.     def set_backup_dir(self):
  436.         '''Setup self.backup_dir, directory where backup files are stored.
  437.         
  438.         This is used for old xorg.conf, DriverDB caches, etc.
  439.         '''
  440.         self.backup_dir = '/var/cache/jockey'
  441.         if not os.path.isdir(self.backup_dir):
  442.             
  443.             try:
  444.                 os.makedirs(self.backup_dir)
  445.             except OSError:
  446.                 e = None
  447.                 logging.error('Could not create %s: %s, using temporary directory; all your caches will be lost!', self.backup_dir, str(e))
  448.                 self.backup_dir = tempfile.mkdtemp(prefix = 'jockey_cache')
  449.             except:
  450.                 None<EXCEPTION MATCH>OSError
  451.             
  452.  
  453.         None<EXCEPTION MATCH>OSError
  454.  
  455.     
  456.     def ignored_modules(self):
  457.         '''Return a set of kernel modules which should be ignored.
  458.  
  459.         This particularly effects free kernel modules which are shipped by the
  460.         OS vendor by default, and thus should not be controlled with this
  461.         program.  Since this will include the large majority of existing kernel
  462.         modules, implementing this is also important for speed reasons; without
  463.         it, detecting existing modules will take quite long.
  464.         
  465.         Note that modules which are ignored here, but covered by a custom
  466.         handler will still be considered.
  467.         '''
  468.         dpkg = subprocess.Popen([
  469.             'dpkg',
  470.             '-L',
  471.             'linux-image-' + os.uname()[2]], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  472.         out = dpkg.communicate()[0]
  473.         result = set()
  474.         if dpkg.returncode == 0:
  475.             for l in out.splitlines():
  476.                 if l.endswith('.ko'):
  477.                     result.add(os.path.splitext(os.path.basename(l))[0].replace('-', '_'))
  478.                     continue
  479.             
  480.         
  481.         dpkg = subprocess.Popen([
  482.             'dpkg',
  483.             '-L',
  484.             'linux-ubuntu-modules-' + os.uname()[2]], stdout = subprocess.PIPE, stderr = subprocess.PIPE)
  485.         out = dpkg.communicate()[0]
  486.         if dpkg.returncode == 0:
  487.             for l in out.splitlines():
  488.                 if l.endswith('.ko'):
  489.                     result.add(os.path.splitext(os.path.basename(l))[0].replace('-', '_'))
  490.                     continue
  491.             
  492.         
  493.         return result
  494.  
  495.     
  496.     def module_blacklisted(self, module):
  497.         '''Check if a module is on the modprobe blacklist.'''
  498.         if not module in self._module_blacklist:
  499.             pass
  500.         return module in self._module_blacklist_system
  501.  
  502.     
  503.     def blacklist_module(self, module, blacklist):
  504.         '''Add or remove a kernel module from the modprobe blacklist.
  505.         
  506.         If blacklist is True, the module is blacklisted, otherwise it is
  507.         removed from the blacklist.
  508.         '''
  509.         if blacklist:
  510.             self._module_blacklist.add(module)
  511.         else:
  512.             
  513.             try:
  514.                 self._module_blacklist.remove(module)
  515.             except KeyError:
  516.                 return None
  517.  
  518.         self._save_module_blacklist()
  519.  
  520.     
  521.     def _load_module_blacklist(self):
  522.         '''Initialize self._module_blacklist{,_system}.'''
  523.         self._module_blacklist = set()
  524.         self._module_blacklist_system = set()
  525.         self._read_blacklist_file(self.module_blacklist_file, self._module_blacklist)
  526.         for f in glob('%s/blacklist*' % os.path.dirname(self.module_blacklist_file)):
  527.             if f != self.module_blacklist_file:
  528.                 self._read_blacklist_file(f, self._module_blacklist_system)
  529.                 continue
  530.         
  531.  
  532.     
  533.     def _read_blacklist_file(klass, path, blacklist_set):
  534.         '''Read a blacklist file and add modules to blacklist_set.'''
  535.         
  536.         try:
  537.             f = open(path)
  538.         except IOError:
  539.             return None
  540.  
  541.         
  542.         try:
  543.             fcntl.flock(f.fileno(), fcntl.LOCK_SH)
  544.             for line in f:
  545.                 line = line[:line.find('#')].strip()
  546.                 if not line.startswith('blacklist'):
  547.                     continue
  548.                 
  549.                 module = line[len('blacklist'):].strip()
  550.                 if module:
  551.                     blacklist_set.add(module)
  552.                     continue
  553.         finally:
  554.             f.close()
  555.  
  556.  
  557.     _read_blacklist_file = classmethod(_read_blacklist_file)
  558.     
  559.     def _save_module_blacklist(self):
  560.         '''Save module blacklist.'''
  561.         if len(self._module_blacklist) == 0 and os.path.exists(self.module_blacklist_file):
  562.             os.unlink(self.module_blacklist_file)
  563.             return None
  564.         os.umask(18)
  565.         d = os.path.dirname(self.module_blacklist_file)
  566.         if not os.path.exists(d):
  567.             os.makedirs(d)
  568.         
  569.         f = open(self.module_blacklist_file, 'w')
  570.         
  571.         try:
  572.             fcntl.flock(f.fileno(), fcntl.LOCK_EX)
  573.             for module in sorted(self._module_blacklist):
  574.                 print >>f, 'blacklist', module
  575.         finally:
  576.             f.close()
  577.  
  578.  
  579.     
  580.     def _get_os_version(self):
  581.         '''Initialize self.os_vendor and self.os_version.
  582.  
  583.         This defaults to reading the values from lsb_release.
  584.         '''
  585.         p = subprocess.Popen([
  586.             'lsb_release',
  587.             '-si'], stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True)
  588.         self.os_vendor = p.communicate()[0].strip()
  589.         p = subprocess.Popen([
  590.             'lsb_release',
  591.             '-sr'], stdout = subprocess.PIPE, stderr = subprocess.PIPE, close_fds = True)
  592.         self.os_version = p.communicate()[0].strip()
  593.         if not p.returncode == 0:
  594.             raise AssertionError
  595.  
  596.     
  597.     def get_system_vendor_product(self):
  598.         """Return (vendor, product) of the system hardware.
  599.  
  600.         Either or both can be '' if they cannot be determined.
  601.  
  602.         The default implementation queries hal.
  603.         """
  604.         
  605.         try:
  606.             hal = subprocess.Popen([
  607.                 self.hal_get_property_path,
  608.                 '--udi',
  609.                 '/org/freedesktop/Hal/devices/computer',
  610.                 '--key',
  611.                 'system.hardware.vendor'], stdout = subprocess.PIPE, close_fds = True)
  612.             vendor = hal.communicate()[0].strip()
  613.             if not hal.returncode == 0:
  614.                 raise AssertionError
  615.         except (OSError, AssertionError):
  616.             vendor = ''
  617.  
  618.         
  619.         try:
  620.             hal = subprocess.Popen([
  621.                 self.hal_get_property_path,
  622.                 '--udi',
  623.                 '/org/freedesktop/Hal/devices/computer',
  624.                 '--key',
  625.                 'system.hardware.product'], stdout = subprocess.PIPE, close_fds = True)
  626.             product = hal.communicate()[0].strip()
  627.             if not hal.returncode == 0:
  628.                 raise AssertionError
  629.         except (OSError, AssertionError):
  630.             product = ''
  631.  
  632.         return (vendor, product)
  633.  
  634.  
  635.