295 lines
8.9 KiB
Python
295 lines
8.9 KiB
Python
# Copyright 2009 Google Inc. Released under the GPL v2
|
|
|
|
import re
|
|
|
|
|
|
class boottool(object):
|
|
"""
|
|
Common class for the client and server side boottool wrappers.
|
|
"""
|
|
|
|
def __init__(self):
|
|
self._xen_mode = False
|
|
|
|
|
|
def _run_boottool(self, *options):
|
|
"""
|
|
Override in derivations to execute the "boottool" command and return
|
|
the stdout output in case of success. In case of failure an exception
|
|
should be raised.
|
|
|
|
@param options: a sequence of command line arguments to give to the
|
|
boottool command
|
|
@return string with the stdout output of the boottool command.
|
|
@raise Exception in case of boottool command failure.
|
|
"""
|
|
raise NotImplementedError('_run_boottool not implemented!')
|
|
|
|
|
|
def get_type(self):
|
|
"""
|
|
Return the installed bootloader type.
|
|
"""
|
|
return self._run_boottool('--bootloader-probe').strip()
|
|
|
|
|
|
def get_architecture(self):
|
|
"""
|
|
Get the system architecture reported by the bootloader.
|
|
"""
|
|
return self._run_boottool('--arch-probe').strip()
|
|
|
|
|
|
def get_titles(self):
|
|
"""
|
|
Returns a list of boot entries titles.
|
|
"""
|
|
return [entry['title'] for entry in self.get_entries().itervalues()]
|
|
|
|
|
|
def get_default(self):
|
|
"""
|
|
Return an int with the # of the default bootloader entry.
|
|
"""
|
|
return int(self._run_boottool('--default').strip())
|
|
|
|
|
|
def set_default(self, index):
|
|
"""
|
|
Set the default boot entry.
|
|
|
|
@param index: entry index number to set as the default.
|
|
"""
|
|
assert index is not None
|
|
self._run_boottool('--set-default=%s' % index)
|
|
|
|
|
|
def get_default_title(self):
|
|
"""
|
|
Get the default entry title.
|
|
|
|
@return a string of the default entry title.
|
|
"""
|
|
return self.get_entry('default')['title']
|
|
|
|
|
|
def _parse_entry(self, entry_str):
|
|
"""
|
|
Parse entry as returned by boottool.
|
|
|
|
@param entry_str: one entry information as returned by boottool
|
|
@return: dictionary of key -> value where key is the string before
|
|
the first ":" in an entry line and value is the string after
|
|
it
|
|
"""
|
|
entry = {}
|
|
for line in entry_str.splitlines():
|
|
if len(line) == 0:
|
|
continue
|
|
name, value = line.split(':', 1)
|
|
name = name.strip()
|
|
value = value.strip()
|
|
|
|
if name == 'index':
|
|
# index values are integrals
|
|
value = int(value)
|
|
entry[name] = value
|
|
|
|
return entry
|
|
|
|
|
|
def get_entry(self, search_info):
|
|
"""
|
|
Get a single bootloader entry information.
|
|
|
|
NOTE: if entry is "fallback" and bootloader is grub
|
|
use index instead of kernel title ("fallback") as fallback is
|
|
a special option in grub
|
|
|
|
@param search_info: can be 'default', position number or title
|
|
@return a dictionary of key->value where key is the type of entry
|
|
information (ex. 'title', 'args', 'kernel', etc) and value
|
|
is the value for that piece of information.
|
|
"""
|
|
return self._parse_entry(self._run_boottool('--info=%s' % search_info))
|
|
|
|
|
|
def get_entries(self):
|
|
"""
|
|
Get all entries information.
|
|
|
|
@return: a dictionary of index -> entry where entry is a dictionary
|
|
of entry information as described for get_entry().
|
|
"""
|
|
raw = "\n" + self._run_boottool('--info=all')
|
|
entries = {}
|
|
for entry_str in raw.split("\nindex"):
|
|
if len(entry_str.strip()) == 0:
|
|
continue
|
|
entry = self._parse_entry("index" + entry_str)
|
|
entries[entry["index"]] = entry
|
|
|
|
return entries
|
|
|
|
|
|
def get_title_for_kernel(self, path):
|
|
"""
|
|
Returns a title for a particular kernel.
|
|
|
|
@param path: path of the kernel image configured in the boot config
|
|
@return: if the given kernel path is found it will return a string
|
|
with the title for the found entry, otherwise returns None
|
|
"""
|
|
entries = self.get_entries()
|
|
for entry in entries.itervalues():
|
|
if entry.get('kernel') == path:
|
|
return entry['title']
|
|
return None
|
|
|
|
|
|
def add_args(self, kernel, args):
|
|
"""
|
|
Add cmdline arguments for the specified kernel.
|
|
|
|
@param kernel: can be a position number (index) or title
|
|
@param args: argument to be added to the current list of args
|
|
"""
|
|
|
|
parameters = ['--update-kernel=%s' % kernel, '--args=%s' % args]
|
|
|
|
#add parameter if this is a Xen entry
|
|
if self._xen_mode:
|
|
parameters.append('--xen')
|
|
|
|
self._run_boottool(*parameters)
|
|
|
|
|
|
def remove_args(self, kernel, args):
|
|
"""
|
|
Removes specified cmdline arguments.
|
|
|
|
@param kernel: can be a position number (index) or title
|
|
@param args: argument to be removed of the current list of args
|
|
"""
|
|
|
|
parameters = ['--update-kernel=%s' % kernel, '--remove-args=%s' % args]
|
|
|
|
#add parameter if this is a Xen entry
|
|
if self._xen_mode:
|
|
parameters.append('--xen')
|
|
|
|
self._run_boottool(*parameters)
|
|
|
|
|
|
def __remove_duplicate_cmdline_args(self, cmdline):
|
|
"""
|
|
Remove the duplicate entries in cmdline making sure that the first
|
|
duplicate occurances are the ones removed and the last one remains
|
|
(this is in order to not change the semantics of the "console"
|
|
parameter where the last occurance has special meaning)
|
|
|
|
@param cmdline: a space separate list of kernel boot parameters
|
|
(ex. 'console=ttyS0,57600n8 nmi_watchdog=1')
|
|
@return: a space separated list of kernel boot parameters without
|
|
duplicates
|
|
"""
|
|
copied = set()
|
|
new_args = []
|
|
|
|
for arg in reversed(cmdline.split()):
|
|
if arg not in copied:
|
|
new_args.insert(0, arg)
|
|
copied.add(arg)
|
|
return ' '.join(new_args)
|
|
|
|
|
|
def add_kernel(self, path, title='autoserv', root=None, args=None,
|
|
initrd=None, default=False, position='end',
|
|
xen_hypervisor=None):
|
|
"""
|
|
Add a kernel entry to the bootloader (or replace if one exists
|
|
already with the same title).
|
|
|
|
@param path: string path to the kernel image file
|
|
@param title: title of this entry in the bootloader config
|
|
@param root: string of the root device
|
|
@param args: string with cmdline args
|
|
@param initrd: string path to the initrd file
|
|
@param default: set to True to make this entry the default one
|
|
(default False)
|
|
@param position: where to insert the new entry in the bootloader
|
|
config file (default 'end', other valid input 'start', or
|
|
# of the title)
|
|
@param xen_hypervisor: xen hypervisor image file (valid only when
|
|
xen mode is enabled)
|
|
"""
|
|
if title in self.get_titles():
|
|
self.remove_kernel(title)
|
|
|
|
parameters = ['--add-kernel=%s' % path, '--title=%s' % title]
|
|
|
|
if root:
|
|
parameters.append('--root=%s' % root)
|
|
|
|
if args:
|
|
parameters.append('--args=%s' %
|
|
self.__remove_duplicate_cmdline_args(args))
|
|
|
|
if initrd:
|
|
parameters.append('--initrd=%s' % initrd)
|
|
|
|
if default:
|
|
parameters.append('--make-default')
|
|
|
|
if position:
|
|
parameters.append('--position=%s' % position)
|
|
|
|
# add parameter if this is a Xen entry
|
|
if self._xen_mode:
|
|
parameters.append('--xen')
|
|
if xen_hypervisor:
|
|
parameters.append('--xenhyper=%s' % xen_hypervisor)
|
|
|
|
self._run_boottool(*parameters)
|
|
|
|
|
|
def remove_kernel(self, kernel):
|
|
"""
|
|
Removes a specific entry from the bootloader configuration.
|
|
|
|
@param kernel: can be 'start', 'end', entry position or entry title.
|
|
"""
|
|
self._run_boottool('--remove-kernel=%s' % kernel)
|
|
|
|
|
|
def boot_once(self, title=None):
|
|
"""
|
|
Sets a specific entry for the next boot, then falls back to the
|
|
default kernel.
|
|
|
|
@param kernel: title that identifies the entry to set for booting. If
|
|
evaluates to false, this becomes a no-op.
|
|
"""
|
|
if title:
|
|
self._run_boottool('--boot-once', '--title=%s' % title)
|
|
|
|
|
|
def enable_xen_mode(self):
|
|
"""
|
|
Enables xen mode. Future operations will assume xen is being used.
|
|
"""
|
|
self._xen_mode = True
|
|
|
|
|
|
def disable_xen_mode(self):
|
|
"""
|
|
Disables xen mode.
|
|
"""
|
|
self._xen_mode = False
|
|
|
|
|
|
def get_xen_mode(self):
|
|
"""
|
|
Returns a boolean with the current status of xen mode.
|
|
"""
|
|
return self._xen_mode
|