def ConfigureService(serviceName, description, lsbStartDep, lsbStopDep, lsbStartBefore,
                     lsbStopAfter, chkcfgStartLevel, chkcfgStopLevel):
   """
   Configure a service using the program appropriate for the current system.
   Right now we support insserv, chkconfig, and update-rc.d

   ********                        READ ME ...  IMPORTANT!
   ********
   ******** This function expects the component using it to have the initinfo scripts in
   ******** initinfo/initinfo.*.  They shouldn't be installed, they should just be included
   ******** in the component.  Without them, it will fail.
   ********

   @param serviceName: The service name, matches the script name
   @param description: Text description of the service.  Single-line only
   @param lsbStartDep: Space separated list of services that must be started *before* this service.
   @param lsbStopDep: Space separated list of services that must be stopped *after* this service.
   @param lsbStartBefore: Space separated list of reverse deps.  This package must start before these.
   @param lsbStopAfter: Space separated list of reverse deps.  This package must stop after these.
   @param chkcfgStartLevel: The start number for chkconfig or update-rc.d scripts
   @param chkcfgStopLevel: The stop number for chkconfig or update-rc.d scripts
   """
   scriptFile = INITSCRIPTDIR/serviceName
   if not INITSCRIPTDIR or not scriptFile.exists():
      # TODO: Raise a dialog informing the user that we are unable to add init script links.
      # TODO: This can take the place of Workstation's current message for Gentoo and Arch
      # TODO: systems.
      return
   script = scriptFile.bytes()

   (initType, initProgram) = InitConfigProgram()

   if not initType:
      # We can't use a program to do it for us, lay down the links ourselves.
      if not INITDIR:
         # TODO: Raise a dialog informing the user that we are unable to add init script links.
         # TODO: This can take the place of Workstation's current message for Gentoo and Arch
         # TODO: systems.
         log.Warn(u'INITDIR has not been set.  No rc?.d style dirs '
                    u'to populate.')
         return

      script = INITSCRIPTDIR/serviceName
      pattern = 'rc%(runlevel)d.d/%(letter)s%(priority)02d%(name)s'

      for runlevel in (2, 3, 5):
         # Build symlinks for this runlevel
         startLink = path(INITDIR/(pattern % {'runlevel': runlevel, 'letter': 'S',
                                              'priority': chkcfgStartLevel, 'name': serviceName}))
         stopLink = path(INITDIR/(pattern % {'runlevel': runlevel, 'letter': 'K',
                                             'priority': chkcfgStopLevel, 'name': serviceName}))
         try:
            script.symlink(startLink)
         except OSError as e:
            pass # Okay if it already exists
         try:
            script.symlink(stopLink)
         except OSError as e:
            pass # Okay if it already exists

         # Register files with the installer.  It will clean them up on uninstall.
         inst.RegisterFile(startLink)
         inst.RegisterFile(stopLink)

   if initType == 'insserv':
      # Add the insserv style header and add our service
      initheader = inst.GetFileText('initinfo/initinfo.lsb')
      initheader = re.sub('@@SERVICE_NAME@@', serviceName, initheader)
      initheader = re.sub('@@LSB_SERVICE_START_DEP@@', lsbStartDep, initheader)
      initheader = re.sub('@@LSB_SERVICE_STOP_DEP@@', lsbStopDep, initheader)
      initheader = re.sub('@@LSB_SERVICE_START_BEFORE_DEP@@', lsbStartBefore, initheader)
      initheader = re.sub('@@LSB_SERVICE_STOP_AFTER_DEP@@', lsbStopAfter, initheader)
      initheader = re.sub('@@SERVICE_DESCRIPTION@@', description, initheader)
      txt = re.sub('# VMWARE_INIT_INFO', initheader, script, re.DOTALL)
      scriptFile.write_bytes(txt)
      inst.RunCommand('/bin/sh', '-c', '%s -f %s >/dev/null 2>&1' % (initProgram, serviceName), ignoreErrors=True)

   if initType == 'chkconfig':
      # Add the chkconfig style header and add our service
      initheader = inst.GetFileText('initinfo/initinfo.chkconfig')
      initheader = re.sub('@@CHKCFG_START_LEVEL@@', str(chkcfgStartLevel), initheader)
      initheader = re.sub('@@CHKCFG_STOP_LEVEL@@', str(chkcfgStopLevel), initheader)
      initheader = re.sub('@@SERVICE_DESCRIPTION@@', description, initheader)
      txt = re.sub('# VMWARE_INIT_INFO', initheader, script, re.DOTALL)
      scriptFile.write_bytes(txt)
      inst.RunCommand(initProgram, '--add', serviceName, ignoreErrors=True)

   if initType == 'update-rc.d':
      # Add the insserv style header and add our service
      initheader = inst.GetFileText('initinfo/initinfo.updaterc')
      initheader = re.sub('@@SERVICE_NAME@@', serviceName, initheader)
      initheader = re.sub('@@LSB_SERVICE_START_DEP@@', lsbStartDep, initheader)
      initheader = re.sub('@@LSB_SERVICE_STOP_DEP@@', lsbStopDep, initheader)
      initheader = re.sub('@@LSB_SERVICE_START_BEFORE_DEP@@', lsbStartBefore, initheader)
      initheader = re.sub('@@LSB_SERVICE_STOP_AFTER_DEP@@', lsbStopAfter, initheader)
      initheader = re.sub('@@SERVICE_DESCRIPTION@@', description, initheader)
      txt = re.sub('# VMWARE_INIT_INFO', initheader, script, re.DOTALL)
      scriptFile.write_bytes(txt)
      inst.RunCommand(initProgram, serviceName,
                      'start', chkcfgStartLevel, '2', '3', '4', '.', 
                      'stop', chkcfgStopLevel, '0', '6', '.', ignoreErrors=True)

   log.Info('Installed Service: %s' % serviceName)

def DeconfigureService(serviceName):
   (initType, initProgram) = InitConfigProgram()
   if not initType:
      # The links have been registered with the installer.  It will remove them on
      # uninstall.
      pass

   if initType == 'insserv':
      inst.RunCommand('/bin/sh', '-c', '%s -f -r %s >/dev/null 2>&1' % (initProgram, serviceName), ignoreErrors=True)
   if initType == 'chkconfig':
      inst.RunCommand(initProgram, '--del', serviceName, ignoreErrors=True)
   if initType == 'update-rc.d':
      inst.RunCommand(initProgram, '-f', serviceName, 'remove', ignoreErrors=True)

   log.Info('Uninstalled Service: %s' % serviceName)

def InitConfigProgram():
   """
   Scan the system to try and guess the program that sets up the init script links.
   On RHEL, it's chkconfig, on SuSE it's insserv, and on Ubuntu it's update-rc.d.

   NOTE: Don't use insserv on Ubuntu per bug 776485.  Ubuntu so very wisely ships
         it but expects developers not to use it.
   """

   # First, check for update-rc.d b/c we want to use it instead
   # of insserv on Ubuntu and Debian systems.
   if path('/usr/sbin/update-rc.d').isexe():
      return ('update-rc.d', '/usr/sbin/update-rc.d')
   elif path('/sbin/update-rc.d').isexe():
      return ('update-rc.d', '/sbin/update-rc.d')
   elif (_which('update-rc.d')):
      return ('update-rc.d', _which('update-rc.d'))

   if path('/sbin/insserv').isexe():
      return ('insserv', '/sbin/insserv')
   elif _which('insserv'):
      return ('insserv', _which('insserv'))

   if path('/sbin/chkconfig').isexe():
      return ('chkconfig', '/sbin/chkconfig')
   elif (_which('chkconfig')):
      return ('chkconfig', _which('chkconfig'))

   # XXX: Add support for upstart in the future.

   return (None, None)

def _which(program):
   """
   Gets the PATH environment variable and checks for program
   in order.

   @param program: Executable to search for
   @returns: Full path if found and executable, None otherwise
   """
   # XXX: Borrowed from util/shell.py.  This should be broken into a
   # utility file to be used by both components and the main code.
   systemPath = ENV['PATH']
   paths = systemPath.split(':')
   for p in paths:
      fullPath = path(p)/program
      if fullPath.isexe():
         return str(fullPath) # Return a string, not a path object

   return None
