# 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
|