[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.