debuggers.hg

changeset 20921:d0b431ede24b

pygrub: support parsing of syslinux configuration files

Allows booting from ISOs which use isolinux as well as guests using
extlinux.

Also add copyright header to GrubConf.py, I think the grub2 support
added last year qualifies as a substantial change.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Feb 01 14:03:47 2010 +0000 (2010-02-01)
parents 5668c36282ea
children 4e8ce74fb8bb
files tools/pygrub/src/ExtLinuxConf.py tools/pygrub/src/GrubConf.py tools/pygrub/src/pygrub
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/tools/pygrub/src/ExtLinuxConf.py	Mon Feb 01 14:03:47 2010 +0000
     1.3 @@ -0,0 +1,200 @@
     1.4 +#
     1.5 +# ExtLinuxConf.py - Simple syslinux config parsing
     1.6 +#
     1.7 +# Copyright 2010 Citrix Systems Ltd.
     1.8 +#
     1.9 +# This software may be freely redistributed under the terms of the GNU
    1.10 +# general public license.
    1.11 +#
    1.12 +# You should have received a copy of the GNU General Public License
    1.13 +# along with this program; if not, write to the Free Software
    1.14 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    1.15 +#
    1.16 +
    1.17 +import sys, re, os
    1.18 +import logging
    1.19 +import GrubConf
    1.20 +
    1.21 +class ExtLinuxImage(object):
    1.22 +    def __init__(self, lines, path):
    1.23 +        self.reset(lines, path)
    1.24 +
    1.25 +    def __repr__(self):
    1.26 +        return ("title: %s\n"
    1.27 +                "  root: %s\n"
    1.28 +                "  kernel: %s\n"
    1.29 +                "  args: %s\n"
    1.30 +                "  initrd: %s\n" %(self.title, self.root, self.kernel,
    1.31 +                                   self.args, self.initrd))
    1.32 +    def reset(self, lines, path):
    1.33 +        self._initrd = self._kernel = self._readonly = None
    1.34 +        self._args = ""
    1.35 +        self.title = ""
    1.36 +        self.lines = []
    1.37 +        self.path = path
    1.38 +        self.root = ""
    1.39 +        map(self.set_from_line, lines)
    1.40 +
    1.41 +    def set_from_line(self, line, replace = None):
    1.42 +        (com, arg) = GrubConf.grub_exact_split(line, 2)
    1.43 +        com = com.lower()
    1.44 +
    1.45 +        # Special handling for mboot.c32
    1.46 +        if com.lower() == "append" and self.kernel is not None:
    1.47 +            (_,kernel) = self.kernel
    1.48 +            if kernel.endswith("mboot.c32"):
    1.49 +                kernel = None
    1.50 +                args = None
    1.51 +                initrd = None
    1.52 +                modules = arg.split("---")
    1.53 +
    1.54 +                if len(modules) == 3: # Assume Xen + Kernel + Initrd
    1.55 +                    (_,kernel,initrd) = modules
    1.56 +                elif len(modules) == 2: # Assume Kernel + Initrd
    1.57 +                    (kernel,initrd) = modules
    1.58 +
    1.59 +                if kernel:
    1.60 +                    setattr(self, "kernel", kernel.strip())
    1.61 +                if initrd:
    1.62 +                    setattr(self, "initrd", initrd.strip())
    1.63 +
    1.64 +                # Bypass regular self.commands handling
    1.65 +                com = None
    1.66 +
    1.67 +        if com is not None and self.commands.has_key(com):
    1.68 +            if self.commands[com] is not None:
    1.69 +                setattr(self, self.commands[com], re.sub('^"(.+)"$', r"\1", arg.strip()))
    1.70 +            else:
    1.71 +                logging.info("Ignored image directive %s" %(com,))
    1.72 +        elif com is not None:
    1.73 +            logging.warning("Unknown image directive %s" %(com,))
    1.74 +
    1.75 +        # now put the line in the list of lines
    1.76 +        if replace is None:
    1.77 +            self.lines.append(line)
    1.78 +        else:
    1.79 +            self.lines.pop(replace)
    1.80 +            self.lines.insert(replace, line)
    1.81 +
    1.82 +    def set_kernel(self, val):
    1.83 +        if val.find(" ") == -1:
    1.84 +            self._kernel = (None,val)
    1.85 +            self._args = None
    1.86 +            return
    1.87 +        (kernel, args) = val.split(None, 1)
    1.88 +        self._kernel = (None,kernel)
    1.89 +        self._args = args
    1.90 +    def get_kernel(self):
    1.91 +        return self._kernel
    1.92 +    def get_args(self):
    1.93 +        return self._args
    1.94 +    kernel = property(get_kernel, set_kernel)
    1.95 +    args = property(get_args)
    1.96 +
    1.97 +    def set_initrd(self, val):
    1.98 +        self._initrd = (None,val)
    1.99 +    def get_initrd(self):
   1.100 +        return self._initrd
   1.101 +    initrd = property(get_initrd, set_initrd)
   1.102 +
   1.103 +    def set_readonly(self, val):
   1.104 +        self._readonly = 1
   1.105 +    def get_readonly(self):
   1.106 +        return self._readonly
   1.107 +    readonly = property(get_readonly, set_readonly)
   1.108 +
   1.109 +    # set up command handlers
   1.110 +    commands = {
   1.111 +        "label": "title",
   1.112 +        "kernel": "kernel",
   1.113 +        "append": "args"}
   1.114 +
   1.115 +class ExtLinuxConfigFile(object):
   1.116 +    def __init__(self, fn = None):
   1.117 +        self.filename = fn
   1.118 +        self.images = []
   1.119 +        self.timeout = -1
   1.120 +        self._default = 0
   1.121 +
   1.122 +        if fn is not None:
   1.123 +            self.parse()
   1.124 +
   1.125 +    def parse(self, buf = None):
   1.126 +        if buf is None:
   1.127 +            if self.filename is None:
   1.128 +                raise ValueError, "No config file defined to parse!"
   1.129 +
   1.130 +            f = open(self.filename, 'r')
   1.131 +            lines = f.readlines()
   1.132 +            f.close()
   1.133 +        else:
   1.134 +            lines = buf.split("\n")
   1.135 +
   1.136 +        path = os.path.dirname(self.filename)
   1.137 +        img = []
   1.138 +        for l in lines:
   1.139 +            l = l.strip()
   1.140 +            # skip blank lines
   1.141 +            if len(l) == 0:
   1.142 +                continue
   1.143 +            # skip comments
   1.144 +            if l.startswith('#'):
   1.145 +                continue
   1.146 +            # new image
   1.147 +            if l.lower().startswith("label"):
   1.148 +                if len(img) > 0:
   1.149 +                    self.add_image(ExtLinuxImage(img, path))
   1.150 +                img = [l]
   1.151 +                continue
   1.152 +
   1.153 +            if len(img) > 0:
   1.154 +                img.append(l)
   1.155 +                continue
   1.156 +
   1.157 +            (com, arg) = GrubConf.grub_exact_split(l, 2)
   1.158 +            com = com.lower()
   1.159 +            if self.commands.has_key(com):
   1.160 +                if self.commands[com] is not None:
   1.161 +                    setattr(self, self.commands[com], arg.strip())
   1.162 +                else:
   1.163 +                    logging.info("Ignored directive %s" %(com,))
   1.164 +            else:
   1.165 +                logging.warning("Unknown directive %s" %(com,))
   1.166 +
   1.167 +        if len(img) > 0:
   1.168 +            self.add_image(ExtLinuxImage(img, path))
   1.169 +
   1.170 +    def hasPassword(self):
   1.171 +        return False
   1.172 +
   1.173 +    def hasPasswordAccess(self):
   1.174 +        return True
   1.175 +
   1.176 +    def add_image(self, image):
   1.177 +        self.images.append(image)
   1.178 +
   1.179 +    def _get_default(self):
   1.180 +        for i in range(len(self.images)):
   1.181 +            if self.images[i].title == self._default:
   1.182 +                return i
   1.183 +        return 0
   1.184 +    def _set_default(self, val):
   1.185 +        self._default = val
   1.186 +    default = property(_get_default, _set_default)
   1.187 +
   1.188 +    commands = { "default": "default",
   1.189 +                 "timeout": "timeout",
   1.190 +                 "serial": None,
   1.191 +                 "prompt": None,
   1.192 +                 "display": None,
   1.193 +                 "f1": None,
   1.194 +                 "f2": None,
   1.195 +                 }
   1.196 +        
   1.197 +if __name__ == "__main__":
   1.198 +    if sys.argv < 2:
   1.199 +        raise RuntimeError, "Need a configuration file to read"
   1.200 +    g = ExtLinuxConfigFile(sys.argv[1])
   1.201 +    for i in g.images:
   1.202 +        print i
   1.203 +    print g.default
     2.1 --- a/tools/pygrub/src/GrubConf.py	Mon Feb 01 14:03:06 2010 +0000
     2.2 +++ b/tools/pygrub/src/GrubConf.py	Mon Feb 01 14:03:47 2010 +0000
     2.3 @@ -1,6 +1,7 @@
     2.4  #
     2.5  # GrubConf.py - Simple grub.conf parsing
     2.6  #
     2.7 +# Copyright 2009 Citrix Systems Inc.
     2.8  # Copyright 2005-2006 Red Hat, Inc.
     2.9  # Jeremy Katz <katzj@redhat.com>
    2.10  #
     3.1 --- a/tools/pygrub/src/pygrub	Mon Feb 01 14:03:06 2010 +0000
     3.2 +++ b/tools/pygrub/src/pygrub	Mon Feb 01 14:03:47 2010 +0000
     3.3 @@ -24,6 +24,7 @@ import getopt
     3.4  import fsimage
     3.5  import grub.GrubConf
     3.6  import grub.LiloConf
     3.7 +import grub.ExtLinuxConf
     3.8  
     3.9  PYGRUB_VER = 0.6
    3.10  
    3.11 @@ -383,7 +384,10 @@ class Grub:
    3.12                             ["/boot/grub/menu.lst", "/boot/grub/grub.conf",
    3.13                              "/grub/menu.lst", "/grub/grub.conf"]) + \
    3.14                         map(lambda x: (x,grub.GrubConf.Grub2ConfigFile),
    3.15 -                           ["/boot/grub/grub.cfg"])
    3.16 +                           ["/boot/grub/grub.cfg"]) + \
    3.17 +                       map(lambda x: (x,grub.ExtLinuxConf.ExtLinuxConfigFile),
    3.18 +                           ["/boot/isolinux/isolinux.cfg",
    3.19 +                            "/boot/extlinux.conf"])
    3.20  
    3.21          if not fs:
    3.22              # set the config file and parse it