WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-3.4-testing] pygrub: factor generic Grub functional

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-3.4-testing] pygrub: factor generic Grub functionality into GrubConf base classes
From: "Xen patchbot-3.4-testing" <patchbot-3.4-testing@xxxxxxxxxxxxxxxxxxx>
Date: Tue, 02 Mar 2010 06:10:31 -0800
Delivery-date: Tue, 02 Mar 2010 06:12:01 -0800
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# 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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-3.4-testing] pygrub: factor generic Grub functionality into GrubConf base classes, Xen patchbot-3.4-testing <=