[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-3.4-testing] pygrub: factor generic Grub functionality into GrubConf base classes
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1267538185 0 # Node ID d016a6777167113d53bfa2046f2a9828478c812b # Parent 2b0908b101de382a662be8c3b2f48112fc420202 pygrub: factor generic Grub functionality into GrubConf base classes and inherit from these classes to implement Grub-legacy functionality. Use a tuple of (parser-object,configuration-file) in pygrub to allow for multiple parsers. Makes way for grub2 support. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> xen-unstable changeset: 20485:086a6a0c3f37 xen-unstable date: Mon Nov 23 08:05:49 2009 +0000 pygrub: track the title of an item as an independant field separate to the other fields. This makes the list of lines within a GrubImage 0 based rather than 1 based therefore adjust the user interface parts to suit. This is in preparation for grub2 support where the syntax for the item title does not fit the existing usage. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> xen-unstable changeset: 20486:6e32b7a3e802 xen-unstable date: Mon Nov 23 08:06:19 2009 +0000 pygrub: add basic support for parsing grub2 style grub.cfg file This represents a very simplistic aproach to parsing these file. It is basically sufficient to parse the files produced by Debian Squeeze's version of update-grub. The actual grub.cfg syntax is much more expresive but not apparently documented apart from a few examples... Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> xen-unstable changeset: 20487:c8caa281a75a xen-unstable date: Mon Nov 23 08:06:54 2009 +0000 pygrub: improve grub 2 support * The "default" value can be a quoted string (containing an integer) so strip the quotes before interpreting. * The "set" command takes a variable with an arbitrary name so instead of whitelisting the ones to ignore simply silently accept any set command with an unknown variable. * Ignore the echo command. * Handle the function { ... } syntax. Previously pygrub would error out with a syntax error on the closing "}" because it thought it was the closing bracket of a menuentry. This makes pygrub2 work with the configuration files generated by Debian Squeeze today. Signed-off-by: Ian Campbell <ian.campbell@xxxxxxxxxx> xen-unstable changeset: 20858:2636e5619708 xen-unstable date: Tue Jan 26 15:54:40 2010 +0000 --- tools/pygrub/src/GrubConf.py | 292 ++++++++++++++++++++++++++++++++----------- tools/pygrub/src/pygrub | 36 ++--- 2 files changed, 240 insertions(+), 88 deletions(-) diff -r 2b0908b101de -r d016a6777167 tools/pygrub/src/GrubConf.py --- a/tools/pygrub/src/GrubConf.py Tue Mar 02 13:49:21 2010 +0000 +++ b/tools/pygrub/src/GrubConf.py Tue Mar 02 13:56:25 2010 +0000 @@ -14,6 +14,7 @@ import os, sys import logging +import re def grub_split(s, maxsplit = -1): eq = s.find('=') @@ -78,9 +79,10 @@ class GrubDiskPart(object): self._part = int(val) part = property(get_part, set_part) -class GrubImage(object): - def __init__(self, lines): +class _GrubImage(object): + def __init__(self, title, lines): self.reset(lines) + self.title = title.strip() def __repr__(self): return ("title: %s\n" @@ -89,30 +91,13 @@ class GrubImage(object): " args: %s\n" " initrd: %s\n" %(self.title, self.root, self.kernel, self.args, self.initrd)) + def _parse(self, lines): + map(self.set_from_line, lines) def reset(self, lines): self._root = self._initrd = self._kernel = self._args = None - self.title = "" self.lines = [] - map(self.set_from_line, lines) - - def set_from_line(self, line, replace = None): - (com, arg) = grub_exact_split(line, 2) - - if self.commands.has_key(com): - if self.commands[com] is not None: - setattr(self, self.commands[com], arg.strip()) - else: - logging.info("Ignored image directive %s" %(com,)) - else: - logging.warning("Unknown image directive %s" %(com,)) - - # now put the line in the list of lines - if replace is None: - self.lines.append(line) - else: - self.lines.pop(replace) - self.lines.insert(replace, line) + self._parse(lines) def set_root(self, val): self._root = GrubDiskPart(val) @@ -141,17 +126,37 @@ class GrubImage(object): return self._initrd initrd = property(get_initrd, set_initrd) +class GrubImage(_GrubImage): + def __init__(self, title, lines): + _GrubImage.__init__(self, title, lines) + + def set_from_line(self, line, replace = None): + (com, arg) = grub_exact_split(line, 2) + + if self.commands.has_key(com): + if self.commands[com] is not None: + setattr(self, self.commands[com], arg.strip()) + else: + logging.info("Ignored image directive %s" %(com,)) + else: + logging.warning("Unknown image directive %s" %(com,)) + + # now put the line in the list of lines + if replace is None: + self.lines.append(line) + else: + self.lines.pop(replace) + self.lines.insert(replace, line) + # set up command handlers - commands = { "title": "title", - "root": "root", + commands = { "root": "root", "rootnoverify": "root", "kernel": "kernel", "initrd": "initrd", "chainloader": None, "module": None} - - -class GrubConfigFile(object): + +class _GrubConfigFile(object): def __init__(self, fn = None): self.filename = fn self.images = [] @@ -162,47 +167,7 @@ class GrubConfigFile(object): self.parse() def parse(self, buf = None): - if buf is None: - if self.filename is None: - raise ValueError, "No config file defined to parse!" - - f = open(self.filename, 'r') - lines = f.readlines() - f.close() - else: - lines = buf.split("\n") - - img = [] - for l in lines: - l = l.strip() - # skip blank lines - if len(l) == 0: - continue - # skip comments - if l.startswith('#'): - continue - # new image - if l.startswith("title"): - if len(img) > 0: - self.add_image(GrubImage(img)) - img = [l] - continue - - if len(img) > 0: - img.append(l) - continue - - (com, arg) = grub_exact_split(l, 2) - if self.commands.has_key(com): - if self.commands[com] is not None: - setattr(self, self.commands[com], arg.strip()) - else: - logging.info("Ignored directive %s" %(com,)) - else: - logging.warning("Unknown directive %s" %(com,)) - - if len(img) > 0: - self.add_image(GrubImage(img)) + raise RuntimeError, "unimplemented parse function" def set(self, line): (com, arg) = grub_exact_split(line, 2) @@ -220,6 +185,7 @@ class GrubConfigFile(object): def _get_default(self): return self._default def _set_default(self, val): + val = val.strip("\"") if val == "saved": self._default = 0 else: @@ -248,10 +214,192 @@ class GrubConfigFile(object): commands[c] = None del c - +class GrubConfigFile(_GrubConfigFile): + def __init__(self, fn = None): + _GrubConfigFile.__init__(self,fn) + + def parse(self, buf = None): + if buf is None: + if self.filename is None: + raise ValueError, "No config file defined to parse!" + + f = open(self.filename, 'r') + lines = f.readlines() + f.close() + else: + lines = buf.split("\n") + + img = None + title = "" + for l in lines: + l = l.strip() + # skip blank lines + if len(l) == 0: + continue + # skip comments + if l.startswith('#'): + continue + # new image + if l.startswith("title"): + if img is not None: + self.add_image(GrubImage(title, img)) + img = [] + title = l[6:] + continue + + if img is not None: + img.append(l) + continue + + (com, arg) = grub_exact_split(l, 2) + if self.commands.has_key(com): + if self.commands[com] is not None: + setattr(self, self.commands[com], arg.strip()) + else: + logging.info("Ignored directive %s" %(com,)) + else: + logging.warning("Unknown directive %s" %(com,)) + + if img: + self.add_image(GrubImage(title, img)) + + if self.hasPassword(): + self.setPasswordAccess(False) + +class Grub2Image(_GrubImage): + def __init__(self, title, lines): + _GrubImage.__init__(self, title, lines) + + def set_from_line(self, line, replace = None): + (com, arg) = grub_exact_split(line, 2) + + if com == "set": + (com,arg) = grub_split(arg,2) + com="set:" + com + + if self.commands.has_key(com): + if self.commands[com] is not None: + setattr(self, self.commands[com], arg.strip()) + else: + logging.info("Ignored image directive %s" %(com,)) + elif com.startswith('set:'): + pass + else: + logging.warning("Unknown image directive %s" %(com,)) + + # now put the line in the list of lines + if replace is None: + self.lines.append(line) + else: + self.lines.pop(replace) + self.lines.insert(replace, line) + + commands = {'set:root': 'root', + 'linux': 'kernel', + 'initrd': 'initrd', + 'echo': None, + 'insmod': None, + 'search': None} + +class Grub2ConfigFile(_GrubConfigFile): + def __init__(self, fn = None): + _GrubConfigFile.__init__(self, fn) + + def parse(self, buf = None): + if buf is None: + if self.filename is None: + raise ValueError, "No config file defined to parse!" + + f = open(self.filename, 'r') + lines = f.readlines() + f.close() + else: + lines = buf.split("\n") + + in_function = False + img = None + title = "" + for l in lines: + l = l.strip() + # skip blank lines + if len(l) == 0: + continue + # skip comments + if l.startswith('#'): + continue + + # skip function declarations + if l.startswith('function'): + in_function = True + continue + if in_function: + if l.startswith('}'): + in_function = False + continue + + # new image + title_match = re.match('^menuentry "(.*)" {', l) + if title_match: + if img is not None: + raise RuntimeError, "syntax error 1 %d %s" % (len(img),img) + img = [] + title = title_match.group(1) + continue + + if l.startswith("}"): + if img is None: + raise RuntimeError, "syntax error 2 %d %s" % (len(img),img) + + self.add_image(Grub2Image(title, img)) + img = None + continue + + if img is not None: + img.append(l) + continue + + (com, arg) = grub_exact_split(l, 2) + + if com == "set": + (com,arg) = grub_split(arg,2) + com="set:" + com + + if self.commands.has_key(com): + if self.commands[com] is not None: + setattr(self, self.commands[com], arg.strip()) + else: + logging.info("Ignored directive %s" %(com,)) + elif com.startswith('set:'): + pass + else: + logging.warning("Unknown directive %s" %(com,)) + + if img is not None: + raise RuntimeError, "syntax error 3 %d %s" % (len(img),img) + + if self.hasPassword(): + self.setPasswordAccess(False) + + commands = {'set:default': 'default', + 'set:root': 'root', + 'set:timeout': 'timeout', + 'terminal': None, + 'insmod': None, + 'load_env': None, + 'save_env': None, + 'search': None, + 'if': None, + 'fi': None, + } + if __name__ == "__main__": - if sys.argv < 2: - raise RuntimeError, "Need a grub.conf to read" - g = GrubConfigFile(sys.argv[1]) + if sys.argv < 3: + raise RuntimeError, "Need a grub version (\"grub\" or \"grub2\") and a grub.conf or grub.cfg to read" + if sys.argv[1] == "grub": + g = GrubConfigFile(sys.argv[2]) + elif sys.argv[1] == "grub2": + g = Grub2ConfigFile(sys.argv[2]) + else: + raise RuntimeError, "Unknown config type %s" % sys.argv[1] for i in g.images: print i #, i.title, i.root, i.kernel, i.args, i.initrd diff -r 2b0908b101de -r d016a6777167 tools/pygrub/src/pygrub --- a/tools/pygrub/src/pygrub Tue Mar 02 13:49:21 2010 +0000 +++ b/tools/pygrub/src/pygrub Tue Mar 02 13:56:25 2010 +0000 @@ -259,13 +259,13 @@ class Grub: self.text_win.move(y - 1, x - 1) self.text_win.noutrefresh() - curline = 1 + curline = 0 img = copy.deepcopy(origimg) while 1: draw() self.entry_win.erase() self.entry_win.box() - for idx in range(1, len(img.lines)): + for idx in range(0, len(img.lines)): # current line should be highlighted if idx == curline: self.entry_win.attron(curses.A_REVERSE) @@ -275,7 +275,7 @@ class Grub: if len(l) > 70: l = l[:69] + ">" - self.entry_win.addstr(idx, 2, l) + self.entry_win.addstr(idx + 1, 2, l) if idx == curline: self.entry_win.attroff(curses.A_REVERSE) self.entry_win.noutrefresh() @@ -308,8 +308,8 @@ class Grub: return # bound at the top and bottom - if curline < 1: - curline = 1 + if curline < 0: + curline = 0 elif curline >= len(img.lines): curline = len(img.lines) - 1 @@ -371,17 +371,19 @@ class Grub: raise RuntimeError, "Unable to access %s" %(fn,) if platform.machine() == 'ia64': - self.cf = grub.LiloConf.LiloConfigFile() - # common distributions - file_list = ("/efi/debian/elilo.conf", "/efi/gentoo/elilo.conf", - "/efi/redflag/elilo.conf", "/efi/redhat/elilo.conf", - "/efi/SuSE/elilo.conf",) - # fallbacks - file_list += ("/efi/boot/elilo.conf", "/elilo.conf",) + cfg_list = map(lambda x: (x,grub.LiloConf.LiloConfigFile), + # common distributions + ["/efi/debian/elilo.conf", "/efi/gentoo/elilo.conf", + "/efi/redflag/elilo.conf", "/efi/redhat/elilo.conf", + "/efi/SuSE/elilo.conf",] + + # fallbacks + ["/efi/boot/elilo.conf", "/elilo.conf",]) else: - self.cf = grub.GrubConf.GrubConfigFile() - file_list = ("/boot/grub/menu.lst", "/boot/grub/grub.conf", - "/grub/menu.lst", "/grub/grub.conf") + cfg_list = map(lambda x: (x,grub.GrubConf.GrubConfigFile), + ["/boot/grub/menu.lst", "/boot/grub/grub.conf", + "/grub/menu.lst", "/grub/grub.conf"]) + \ + map(lambda x: (x,grub.GrubConf.Grub2ConfigFile), + ["/boot/grub/grub.cfg"]) if not fs: # set the config file and parse it @@ -389,8 +391,10 @@ class Grub: self.cf.parse() return - for f in file_list: + for f,parser in cfg_list: if fs.file_exists(f): + print >>sys.stderr, "Using %s to parse %s" % (parser,f) + self.cf = parser() self.cf.filename = f break if self.__dict__.get('cf', None) is None: _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |