ia64/xen-unstable

changeset 4677:20d715ae2dfb

bitkeeper revision 1.1327.2.13 (4270d6c35WpxFmhdkREjmSvk82s-Bg)

Merge Jeremy's pygrub bootloader patch.

Signed-off-by: Jeremy Katz <katzj@redhat.com>
Signed-off-by: Mike Wray <mike.wray@hp.com>
author mjw@wray-m-3.hpl.hp.com
date Thu Apr 28 12:27:47 2005 +0000 (2005-04-28)
parents 6639dd8a166b
children ed1b8fd45247
files .rootkeys tools/Makefile tools/pygrub/Makefile tools/pygrub/setup.py tools/pygrub/src/GrubConf.py tools/pygrub/src/__init__.py tools/pygrub/src/fsys/__init__.py tools/pygrub/src/fsys/ext2/__init__.py tools/pygrub/src/fsys/ext2/ext2module.c tools/pygrub/src/fsys/ext2/test.py tools/pygrub/src/pygrub tools/python/xen/xend/XendBootloader.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/server/blkif.py tools/python/xen/xm/create.py tools/xfrd/xfrd.c
line diff
     1.1 --- a/.rootkeys	Thu Apr 28 08:59:31 2005 +0000
     1.2 +++ b/.rootkeys	Thu Apr 28 12:27:47 2005 +0000
     1.3 @@ -799,6 +799,15 @@ 41adc641dV-0cDLSyzMs5BT8nL7v3Q tools/mis
     1.4  4107986eMWVdBoz4tXYoOscpN_BCYg tools/misc/xensv
     1.5  4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
     1.6  40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
     1.7 +4270cc81g3nSNYCZ1ryCMDEbLtMtbQ tools/pygrub/Makefile
     1.8 +4270cc81EIl7NyaS3Av6IPRk2c2a6Q tools/pygrub/setup.py
     1.9 +4270cc81t7eNCDp4Bhbh58p1CNxaCQ tools/pygrub/src/GrubConf.py
    1.10 +4270d6c2fWF4r5-zF1pSuAFwUZS0aA tools/pygrub/src/__init__.py
    1.11 +4270cc81CzKMiujDPWcaYhu709vGXw tools/pygrub/src/fsys/__init__.py
    1.12 +4270cc81RTIiq9si0dI4YRTRE4KRMw tools/pygrub/src/fsys/ext2/__init__.py
    1.13 +4270cc81YCYa4pexivBD2NdLE2F_Pg tools/pygrub/src/fsys/ext2/ext2module.c
    1.14 +4270cc81o4BL5e8Cs87aSi8EXA5NtQ tools/pygrub/src/fsys/ext2/test.py
    1.15 +4270cc81TS6L_tEO6wSp5wcURcpldQ tools/pygrub/src/pygrub
    1.16  40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile
    1.17  40ffc44dOwe1CcYXGCkYHdG_NxcccA tools/python/logging/logging-0.4.9.2/PKG-INFO
    1.18  40ffc44dpqpgqgrnLfR70PsiBc3liA tools/python/logging/logging-0.4.9.2/README.txt
    1.19 @@ -896,6 +905,7 @@ 41597996WNvJA-DVCBmc0xU9w_XmoA tools/pyt
    1.20  40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py
    1.21  40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py
    1.22  40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py
    1.23 +4270cc81xbweGYhsM4326N3dX1bGHQ tools/python/xen/xend/XendBootloader.py
    1.24  40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py
    1.25  40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py
    1.26  40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py
     2.1 --- a/tools/Makefile	Thu Apr 28 08:59:31 2005 +0000
     2.2 +++ b/tools/Makefile	Thu Apr 28 12:27:47 2005 +0000
     2.3 @@ -11,6 +11,7 @@ SUBDIRS += python
     2.4  SUBDIRS += xfrd
     2.5  SUBDIRS += xcs
     2.6  SUBDIRS += ioemu
     2.7 +SUBDIRS += pygrub
     2.8  
     2.9  .PHONY: all install clean check check_clean
    2.10  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/tools/pygrub/Makefile	Thu Apr 28 12:27:47 2005 +0000
     3.3 @@ -0,0 +1,18 @@
     3.4 +
     3.5 +XEN_ROOT = ../..
     3.6 +include $(XEN_ROOT)/tools/Rules.mk
     3.7 +
     3.8 +all: build
     3.9 +build:
    3.10 +	CFLAGS="$(CFLAGS)" python setup.py build
    3.11 +
    3.12 +ifndef XEN_PYTHON_NATIVE_INSTALL
    3.13 +install: all
    3.14 +	CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr"
    3.15 +else
    3.16 +install: all
    3.17 +	CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
    3.18 +endif
    3.19 +
    3.20 +clean:
    3.21 +	rm -rf build *.pyc *.pyo *.o *.a *~
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/tools/pygrub/setup.py	Thu Apr 28 12:27:47 2005 +0000
     4.3 @@ -0,0 +1,25 @@
     4.4 +from distutils.core import setup, Extension
     4.5 +import os
     4.6 +
     4.7 +extra_compile_args  = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
     4.8 +
     4.9 +# in a perfect world, we'd figure out the fsys modules dynamically
    4.10 +ext2 = Extension("grub.fsys.ext2._pyext2",
    4.11 +                 extra_compile_args = extra_compile_args,
    4.12 +                 libraries = ["ext2fs"],
    4.13 +                 sources = ["src/fsys/ext2/ext2module.c"])
    4.14 +
    4.15 +setup(name='pygrub',
    4.16 +      version='0.1',
    4.17 +      description='Boot loader that looks a lot like grub for Xen',
    4.18 +      author='Jeremy Katz',
    4.19 +      author_email='katzj@redhat.com',
    4.20 +      license='GPL',
    4.21 +      package_dir={'grub': 'src'},
    4.22 +      scripts = ["src/pygrub"],
    4.23 +      packages=['grub',
    4.24 +                'grub.fsys',
    4.25 +                'grub.fsys.ext2'],
    4.26 +      ext_modules = [ext2]
    4.27 +      )
    4.28 +               
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/tools/pygrub/src/GrubConf.py	Thu Apr 28 12:27:47 2005 +0000
     5.3 @@ -0,0 +1,229 @@
     5.4 +#
     5.5 +# GrubConf.py - Simple grub.conf parsing
     5.6 +#
     5.7 +# Copyright 2005 Red Hat, Inc.
     5.8 +# Jeremy Katz <katzj@redhat.com>
     5.9 +#
    5.10 +# This software may be freely redistributed under the terms of the GNU
    5.11 +# general public license.
    5.12 +#
    5.13 +# You should have received a copy of the GNU General Public License
    5.14 +# along with this program; if not, write to the Free Software
    5.15 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    5.16 +#
    5.17 +
    5.18 +import os, sys
    5.19 +import logging
    5.20 +
    5.21 +def grub_split(s, maxsplit = -1):
    5.22 +    """Split a grub option screen separated with either '=' or whitespace."""
    5.23 +    eq = s.find('=')
    5.24 +    if eq == -1:
    5.25 +        return s.split(None, maxsplit)
    5.26 +
    5.27 +    # see which of a space or tab is first
    5.28 +    sp = s.find(' ')
    5.29 +    tab = s.find('\t')
    5.30 +    if (tab != -1 and tab < sp) or (tab != -1 and sp == -1):
    5.31 +        sp = tab
    5.32 +
    5.33 +    if eq != -1 and eq < sp or (eq != -1 and sp == -1):
    5.34 +        return s.split('=', maxsplit)
    5.35 +    else:
    5.36 +        return s.split(None, maxsplit)
    5.37 +
    5.38 +def get_path(s):
    5.39 +    """Returns a tuple of (GrubDiskPart, path) corresponding to string."""
    5.40 +    if not s.startswith('('):
    5.41 +        return (None, s)
    5.42 +    idx = s.find(')')
    5.43 +    if idx == -1:
    5.44 +        raise ValueError, "Unable to find matching ')'"
    5.45 +    d = s[:idx]
    5.46 +    return (GrubDiskPart(d), s[idx + 1:])
    5.47 +
    5.48 +class GrubDiskPart(object):
    5.49 +    def __init__(self, str):
    5.50 +        if str.find(',') != -1:
    5.51 +            (self.disk, self.part) = str.split(",", 2)
    5.52 +        else:
    5.53 +            self.disk = str
    5.54 +            self.part = None
    5.55 +
    5.56 +    def __repr__(self):
    5.57 +        if self.part is not None:
    5.58 +            return "d%dp%d" %(self.disk, self.part)
    5.59 +        else:
    5.60 +            return "d%d" %(self,disk,)
    5.61 +
    5.62 +    def get_disk(self):
    5.63 +        return self._disk
    5.64 +    def set_disk(self, val):
    5.65 +        val = val.replace("(", "").replace(")", "")
    5.66 +        self._disk = int(val[2:])
    5.67 +    disk = property(get_disk, set_disk)
    5.68 +
    5.69 +    def get_part(self):
    5.70 +        return self._part
    5.71 +    def set_part(self, val):
    5.72 +        if val is None:
    5.73 +            self._part = val
    5.74 +            return
    5.75 +        val = val.replace("(", "").replace(")", "")
    5.76 +        self._part = int(val)
    5.77 +    part = property(get_part, set_part)
    5.78 +
    5.79 +class GrubImage(object):
    5.80 +    def __init__(self, lines):
    5.81 +        self._root = self._initrd = self._kernel = self._args = None
    5.82 +        for l in lines:
    5.83 +            (com, arg) = grub_split(l, 1)
    5.84 +
    5.85 +            if self.commands.has_key(com):
    5.86 +                if self.commands[com] is not None:
    5.87 +                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
    5.88 +                else:
    5.89 +                    logging.info("Ignored image directive %s" %(com,))
    5.90 +            else:
    5.91 +                logging.warning("Unknown image directive %s" %(com,))
    5.92 +
    5.93 +    def __repr__(self):
    5.94 +        return ("title: %s\n" 
    5.95 +                "  root: %s\n"
    5.96 +                "  kernel: %s\n"
    5.97 +                "  args: %s\n"
    5.98 +                "  initrd: %s" %(self.title, self.root, self.kernel,
    5.99 +                                   self.args, self.initrd))
   5.100 +
   5.101 +    def set_root(self, val):
   5.102 +        self._root = GrubDiskPart(val)
   5.103 +    def get_root(self):
   5.104 +        return self._root
   5.105 +    root = property(get_root, set_root)
   5.106 +
   5.107 +    def set_kernel(self, val):
   5.108 +        if val.find(" ") == -1:
   5.109 +            self._kernel = get_path(val)
   5.110 +            self._args = None
   5.111 +            return
   5.112 +        (kernel, args) = val.split(None, 1)
   5.113 +        self._kernel = get_path(kernel)
   5.114 +        self._args = args
   5.115 +    def get_kernel(self):
   5.116 +        return self._kernel
   5.117 +    def get_args(self):
   5.118 +        return self._args
   5.119 +    kernel = property(get_kernel, set_kernel)
   5.120 +    args = property(get_args)
   5.121 +
   5.122 +    def set_initrd(self, val):
   5.123 +        self._initrd = get_path(val)
   5.124 +    def get_initrd(self):
   5.125 +        return self._initrd
   5.126 +    initrd = property(get_initrd, set_initrd)
   5.127 +
   5.128 +    # set up command handlers
   5.129 +    commands = { "title": "self.title",
   5.130 +                 "root": "self.root",
   5.131 +                 "rootnoverify": "self.root",
   5.132 +                 "kernel": "self.kernel",
   5.133 +                 "initrd": "self.initrd",
   5.134 +                 "chainloader": None,
   5.135 +                 "module": None}
   5.136 +        
   5.137 +
   5.138 +class GrubConfigFile(object):
   5.139 +    def __init__(self, fn = None):
   5.140 +        self.filename = fn
   5.141 +        self.images = []
   5.142 +        self.timeout = -1
   5.143 +
   5.144 +        if fn is not None:
   5.145 +            self.parse()
   5.146 +
   5.147 +    def parse(self, buf = None):
   5.148 +        if buf is None:
   5.149 +            if self.filename is None:
   5.150 +                raise ValueError, "No config file defined to parse!"
   5.151 +
   5.152 +            f = open(self.filename, 'r')
   5.153 +            lines = f.readlines()
   5.154 +            f.close()
   5.155 +        else:
   5.156 +            lines = buf.split("\n")
   5.157 +
   5.158 +        img = []
   5.159 +        for l in lines:
   5.160 +            l = l.strip()
   5.161 +            # skip blank lines
   5.162 +            if len(l) == 0:
   5.163 +                continue
   5.164 +            # skip comments
   5.165 +            if l.startswith('#'):
   5.166 +                continue
   5.167 +            # new image
   5.168 +            if l.startswith("title"):
   5.169 +                if len(img) > 0:
   5.170 +                    self.images.append(GrubImage(img))
   5.171 +                img = [l]
   5.172 +                continue
   5.173 +                
   5.174 +            if len(img) > 0:
   5.175 +                img.append(l)
   5.176 +                continue
   5.177 +
   5.178 +            try:
   5.179 +                (com, arg) = grub_split(l, 1)
   5.180 +            except ValueError:
   5.181 +                com = l
   5.182 +                arg = ""
   5.183 +
   5.184 +            if self.commands.has_key(com):
   5.185 +                if self.commands[com] is not None:
   5.186 +                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
   5.187 +                else:
   5.188 +                    logging.info("Ignored directive %s" %(com,))
   5.189 +            else:
   5.190 +                logging.warning("Unknown directive %s" %(com,))
   5.191 +                
   5.192 +        if len(img) > 0:
   5.193 +            self.images.append(GrubImage(img))
   5.194 +
   5.195 +    def _get_default(self):
   5.196 +        return self._default
   5.197 +    def _set_default(self, val):
   5.198 +        if val == "saved":
   5.199 +            self._default = -1
   5.200 +        else:
   5.201 +            self._default = int(val)
   5.202 +
   5.203 +        if self._default < 0:
   5.204 +            raise ValueError, "default must be positive number"
   5.205 +    default = property(_get_default, _set_default)
   5.206 +
   5.207 +    def set_splash(self, val):
   5.208 +        self._splash = get_path(val)
   5.209 +    def get_splash(self):
   5.210 +        return self._splash
   5.211 +    splash = property(get_splash, set_splash)
   5.212 +
   5.213 +    # set up command handlers
   5.214 +    commands = { "default": "self.default",
   5.215 +                 "timeout": "self.timeout",
   5.216 +                 "fallback": "self.fallback",
   5.217 +                 "hiddenmenu": "self.hiddenmenu",
   5.218 +                 "splashimage": "self.splash",
   5.219 +                 "password": "self.password" }
   5.220 +    for c in ("bootp", "color", "device", "dhcp", "hide", "ifconfig",
   5.221 +              "pager", "partnew", "parttype", "rarp", "serial",
   5.222 +              "setkey", "terminal", "terminfo", "tftpserver", "unhide"):
   5.223 +        commands[c] = None
   5.224 +    del c
   5.225 +
   5.226 +
   5.227 +if __name__ == "__main__":
   5.228 +    if sys.argv < 2:
   5.229 +        raise RuntimeError, "Need a grub.conf to read"
   5.230 +    g = GrubConfigFile(sys.argv[1])
   5.231 +    for i in g.images:
   5.232 +        print i #, i.title, i.root, i.kernel, i.args, i.initrd
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/tools/pygrub/src/fsys/__init__.py	Thu Apr 28 12:27:47 2005 +0000
     6.3 @@ -0,0 +1,61 @@
     6.4 +#
     6.5 +# Copyright 2005 Red Hat, Inc.
     6.6 +# Jeremy Katz <katzj@xxxxxxxxxx>
     6.7 +#
     6.8 +# This software may be freely redistributed under the terms of the GNU
     6.9 +# general public license.
    6.10 +#
    6.11 +# You should have received a copy of the GNU General Public License
    6.12 +# along with this program; if not, write to the Free Software
    6.13 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    6.14 +#
    6.15 +
    6.16 +import os
    6.17 +import sys
    6.18 +
    6.19 +fstypes = {}
    6.20 +
    6.21 +def register_fstype(x):
    6.22 +    if x.name in fstypes.keys():
    6.23 +        return
    6.24 +    fstypes[x.name] = x
    6.25 +
    6.26 +class FileSystemType(object):
    6.27 +    """A simple representation for a file system that gives a fs name
    6.28 +    and a method for sniffing a file to see if it's of the given fstype."""
    6.29 +    def __init__(self):
    6.30 +        self.name = ""
    6.31 +
    6.32 +    def sniff_magic(self, fn, offset = 0):
    6.33 +        """Look at the filesystem at fn for the appropriate magic starting at
    6.34 +        offset offset."""
    6.35 +        raise RuntimeError, "sniff_magic not implemented"
    6.36 +
    6.37 +    def open_fs(self, fn, offset = 0):
    6.38 +        """Open the given filesystem and return a filesystem object."""
    6.39 +        raise RuntimeError, "open_fs not implemented"
    6.40 +
    6.41 +class FileSystem(object):
    6.42 +    def open(self, name, flags = 0, block_size = 0):
    6.43 +        """Open the fsys on name with given flags and block_size."""
    6.44 +        raise RuntimeError, "open not implemented"
    6.45 +
    6.46 +    def close(self):
    6.47 +        """Close the fsys."""
    6.48 +        raise RuntimeError, "close not implemented"
    6.49 +
    6.50 +    def open_file(self, file, flags = None):
    6.51 +        """Open the file 'name' with the given flags.  The returned object
    6.52 +        should look similar to a native file object."""
    6.53 +        raise RuntimeError, "open_file not implemented"
    6.54 +    
    6.55 +
    6.56 +
    6.57 +mydir = sys.modules['grub.fsys'].__path__[0]
    6.58 +for f in os.listdir(mydir):
    6.59 +    if not os.path.isdir("%s/%s" %(mydir, f)):
    6.60 +        continue
    6.61 +    try:
    6.62 +        exec "import grub.fsys.%s" %(f,)        
    6.63 +    except ImportError, e:
    6.64 +        pass
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/tools/pygrub/src/fsys/ext2/__init__.py	Thu Apr 28 12:27:47 2005 +0000
     7.3 @@ -0,0 +1,38 @@
     7.4 +# Copyright 2005 Red Hat, Inc.
     7.5 +# Jeremy Katz <katzj@redhat.com>
     7.6 +#
     7.7 +# This software may be freely redistributed under the terms of the GNU
     7.8 +# general public license.
     7.9 +#
    7.10 +# You should have received a copy of the GNU General Public License
    7.11 +# along with this program; if not, write to the Free Software
    7.12 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    7.13 +#
    7.14 +
    7.15 +from grub.fsys import register_fstype, FileSystemType
    7.16 +from _pyext2 import *
    7.17 +
    7.18 +import os, struct
    7.19 +
    7.20 +class Ext2FileSystemType(FileSystemType):
    7.21 +    def __init__(self):
    7.22 +        FileSystemType.__init__(self)
    7.23 +        self.name = "ext2"
    7.24 +
    7.25 +    def sniff_magic(self, fn, offset = 0):
    7.26 +        fd = os.open(fn, os.O_RDONLY)
    7.27 +        os.lseek(fd, offset, 0)
    7.28 +        buf = os.read(fd, 2048)
    7.29 +        
    7.30 +        if len(buf) > 1082 and \
    7.31 +               struct.unpack("<H", buf[1080:1082]) == (0xef53,):
    7.32 +            return True
    7.33 +        return False
    7.34 +
    7.35 +    def open_fs(self, fn, offset = 0):
    7.36 +        if not self.sniff_magic(fn, offset):
    7.37 +            raise ValueError, "Not an ext2 filesystem"
    7.38 +        return Ext2Fs(fn)
    7.39 +
    7.40 +register_fstype(Ext2FileSystemType())
    7.41 +
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/tools/pygrub/src/fsys/ext2/ext2module.c	Thu Apr 28 12:27:47 2005 +0000
     8.3 @@ -0,0 +1,332 @@
     8.4 +/*
     8.5 + * ext2module.c - simple python binding for libext2fs
     8.6 + *
     8.7 + * Copyright 2005 Red Hat, Inc.
     8.8 + * Jeremy Katz <katzj@redhat.com>
     8.9 + *
    8.10 + * This software may be freely redistributed under the terms of the GNU
    8.11 + * general public license.
    8.12 + *
    8.13 + * You should have received a copy of the GNU General Public License
    8.14 + * along with this program; if not, write to the Free Software
    8.15 + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
    8.16 + */
    8.17 +
    8.18 +#include <Python.h>
    8.19 +
    8.20 +#include <ext2fs/ext2fs.h>
    8.21 +#include <stdlib.h>
    8.22 +#include <stdio.h>
    8.23 +
    8.24 +#if (PYTHON_API_VERSION >= 1011)
    8.25 +#define PY_PAD 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L
    8.26 +#else
    8.27 +#define PY_PAD 0L,0L,0L,0L
    8.28 +#endif
    8.29 +
    8.30 +
    8.31 +/* global error object */
    8.32 +PyObject *Ext2Error;
    8.33 +
    8.34 +typedef struct _Ext2Fs Ext2Fs;
    8.35 +struct _Ext2Fs {
    8.36 +    PyObject_HEAD;
    8.37 +    ext2_filsys fs;
    8.38 +};
    8.39 +
    8.40 +typedef struct _Ext2File Ext2File;
    8.41 +struct _Ext2File {
    8.42 +    PyObject_HEAD;
    8.43 +    ext2_file_t file;
    8.44 +};
    8.45 +
    8.46 +/* ext2 file object */
    8.47 +
    8.48 +static PyObject *
    8.49 +ext2_file_close (Ext2File *file, PyObject *args)
    8.50 +{
    8.51 +    if (file->file != NULL)
    8.52 +        ext2fs_file_close(file->file);
    8.53 +    Py_INCREF(Py_None);
    8.54 +    return Py_None;
    8.55 +}
    8.56 +
    8.57 +static PyObject *
    8.58 +ext2_file_read (Ext2File *file, PyObject *args)
    8.59 +{
    8.60 +    int err, size = 0;
    8.61 +    size_t n, total = 0;
    8.62 +    PyObject * buffer = NULL;
    8.63 +
    8.64 +    if (file->file == NULL) {
    8.65 +        PyErr_SetString(PyExc_ValueError, "Cannot read from closed file");
    8.66 +        return NULL;
    8.67 +    }
    8.68 +
    8.69 +    if (!PyArg_ParseTuple(args, "|i", &size))
    8.70 +        return NULL;
    8.71 +
    8.72 +    buffer = PyString_FromStringAndSize((char *) NULL, (size) ? size : 4096);
    8.73 +    if (buffer == NULL)
    8.74 +        return buffer;
    8.75 + 
    8.76 +    while (1) {
    8.77 +        err = ext2fs_file_read(file->file, PyString_AS_STRING(buffer) + total, 
    8.78 +                               (size) ? size : 4096, &n);
    8.79 +        if (err) {
    8.80 +            if (buffer != NULL) { Py_DECREF(buffer); }
    8.81 +            Py_DECREF(buffer);
    8.82 +            PyErr_SetString(PyExc_ValueError, "read error");
    8.83 +            return NULL;
    8.84 +        }
    8.85 +
    8.86 +        total += n;
    8.87 +        if (n == 0)
    8.88 +            break;
    8.89 +
    8.90 +        if (size && size == total)
    8.91 +            break;
    8.92 +
    8.93 +        if (!size) {
    8.94 +            _PyString_Resize(&buffer, total + 4096);
    8.95 +        }
    8.96 +    }
    8.97 +
    8.98 +    _PyString_Resize(&buffer, total);
    8.99 +    return buffer;
   8.100 +}
   8.101 +
   8.102 +static void
   8.103 +ext2_file_dealloc (Ext2File * file)
   8.104 +{
   8.105 +    if (file->file != NULL)
   8.106 +        ext2fs_file_close(file->file);
   8.107 +    PyMem_DEL(file);
   8.108 +}
   8.109 +
   8.110 +static struct PyMethodDef Ext2FileMethods[] = {
   8.111 +        { "close",
   8.112 +          (PyCFunction) ext2_file_close,
   8.113 +          METH_VARARGS, NULL },
   8.114 +        { "read",
   8.115 +          (PyCFunction) ext2_file_read,
   8.116 +          METH_VARARGS, NULL },
   8.117 +	{ NULL, NULL, 0, NULL }	
   8.118 +};
   8.119 +
   8.120 +static PyObject *
   8.121 +ext2_file_getattr (Ext2File * file, char * name)
   8.122 +{
   8.123 +        return Py_FindMethod (Ext2FileMethods, (PyObject *) file, name);
   8.124 +}
   8.125 +
   8.126 +static char Ext2FileType__doc__[] = "This is the ext2 filesystem object";
   8.127 +PyTypeObject Ext2FileType = {
   8.128 +	PyObject_HEAD_INIT(&PyType_Type)
   8.129 +	0,				/* ob_size */
   8.130 +	"Ext2File",			/* tp_name */
   8.131 +	sizeof(Ext2File),		/* tp_size */
   8.132 +	0,				/* tp_itemsize */
   8.133 +	(destructor) ext2_file_dealloc, 	/* tp_dealloc */
   8.134 +	0,				/* tp_print */
   8.135 +	(getattrfunc) ext2_file_getattr, 	/* tp_getattr */
   8.136 +	0,				/* tp_setattr */
   8.137 +	0,				/* tp_compare */
   8.138 +	0,				/* tp_repr */
   8.139 +	0,				/* tp_as_number */
   8.140 +	0,	 			/* tp_as_sequence */
   8.141 +	0,				/* tp_as_mapping */
   8.142 +	0,           			/* tp_hash */
   8.143 +	0,                		/* tp_call */
   8.144 +	0,                    		/* tp_str */
   8.145 +	0,				/* tp_getattro */
   8.146 +	0,				/* tp_setattro */
   8.147 +	0,				/* tp_as_buffer */
   8.148 +	0L,	       			/* tp_flags */
   8.149 +	Ext2FileType__doc__,
   8.150 +	PY_PAD
   8.151 +};
   8.152 +
   8.153 +static PyObject *
   8.154 +ext2_file_open (Ext2Fs *fs, char * name, int flags)
   8.155 +{
   8.156 +    int err;
   8.157 +    ext2_file_t f;
   8.158 +    ext2_ino_t ino;
   8.159 +    Ext2File * file;
   8.160 +
   8.161 +    file = (Ext2File *) PyObject_NEW(Ext2File, &Ext2FileType);
   8.162 +    file->file = NULL;
   8.163 +
   8.164 +    err = ext2fs_namei_follow(fs->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &ino);
   8.165 +    if (err) {
   8.166 +        PyErr_SetString(PyExc_ValueError, "unable to open file");
   8.167 +        return NULL;
   8.168 +    }
   8.169 +
   8.170 +    err = ext2fs_file_open(fs->fs, ino, flags, &f);
   8.171 +    if (err) {
   8.172 +        PyErr_SetString(PyExc_ValueError, "unable to open file");
   8.173 +        return NULL;
   8.174 +    }
   8.175 +
   8.176 +    file->file = f;
   8.177 +    return (PyObject *) file;
   8.178 +}
   8.179 +
   8.180 +/* ext2fs object */
   8.181 +
   8.182 +static PyObject *
   8.183 +ext2_fs_close (Ext2Fs *fs, PyObject *args)
   8.184 +{
   8.185 +    if (fs->fs != NULL)
   8.186 +        ext2fs_close(fs->fs);
   8.187 +    Py_INCREF(Py_None);
   8.188 +    return Py_None;
   8.189 +}
   8.190 +
   8.191 +static PyObject *
   8.192 +ext2_fs_open (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
   8.193 +{
   8.194 +    static char *kwlist[] = { "name", "flags", "superblock", 
   8.195 +                              "block_size", NULL };
   8.196 +    char * name;
   8.197 +    int flags = 0, superblock = 0, err;
   8.198 +    unsigned int block_size = 0;
   8.199 +    ext2_filsys efs;
   8.200 +
   8.201 +    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, 
   8.202 +                                     &name, &flags, &superblock, &block_size))
   8.203 +                                     return NULL;
   8.204 +
   8.205 +    if (fs->fs != NULL) {
   8.206 +        PyErr_SetString(PyExc_ValueError, "already have an fs object");
   8.207 +        return NULL;
   8.208 +    }
   8.209 +
   8.210 +    err = ext2fs_open(name, flags, superblock, block_size, 
   8.211 +                      unix_io_manager, &efs);
   8.212 +    if (err) {
   8.213 +        PyErr_SetString(PyExc_ValueError, "unable to open file");
   8.214 +        return NULL;
   8.215 +    }
   8.216 +
   8.217 +    fs->fs = efs;
   8.218 +
   8.219 +    Py_INCREF(Py_None);
   8.220 +    return Py_None;
   8.221 +}
   8.222 +
   8.223 +static PyObject *
   8.224 +ext2_fs_open_file (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
   8.225 +{
   8.226 +    static char *kwlist[] = { "name", "flags", NULL };
   8.227 +    char * name;
   8.228 +    int flags = 0;
   8.229 +
   8.230 +    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist, 
   8.231 +                                     &name, &flags))
   8.232 +                                     return NULL;
   8.233 +
   8.234 +    return ext2_file_open(fs, name, flags);
   8.235 +}
   8.236 +
   8.237 +static void
   8.238 +ext2_fs_dealloc (Ext2Fs * fs)
   8.239 +{
   8.240 +    if (fs->fs != NULL)
   8.241 +        ext2fs_close(fs->fs);
   8.242 +    PyMem_DEL(fs);
   8.243 +}
   8.244 +
   8.245 +static struct PyMethodDef Ext2FsMethods[] = {
   8.246 +        { "close",
   8.247 +          (PyCFunction) ext2_fs_close,
   8.248 +          METH_VARARGS, NULL },
   8.249 +        { "open",
   8.250 +          (PyCFunction) ext2_fs_open,
   8.251 +          METH_VARARGS|METH_KEYWORDS, NULL },
   8.252 +        { "open_file",
   8.253 +          (PyCFunction) ext2_fs_open_file,
   8.254 +          METH_VARARGS|METH_KEYWORDS, NULL },
   8.255 +	{ NULL, NULL, 0, NULL }	
   8.256 +};
   8.257 +
   8.258 +static PyObject *
   8.259 +ext2_fs_getattr (Ext2Fs * fs, char * name)
   8.260 +{
   8.261 +        return Py_FindMethod (Ext2FsMethods, (PyObject *) fs, name);
   8.262 +}
   8.263 +
   8.264 +static char Ext2FsType__doc__[] = "This is the ext2 filesystem object";
   8.265 +PyTypeObject Ext2FsType = {
   8.266 +	PyObject_HEAD_INIT(&PyType_Type)
   8.267 +	0,				/* ob_size */
   8.268 +	"Ext2Fs",			/* tp_name */
   8.269 +	sizeof(Ext2Fs),		/* tp_size */
   8.270 +	0,				/* tp_itemsize */
   8.271 +	(destructor) ext2_fs_dealloc, 	/* tp_dealloc */
   8.272 +	0,				/* tp_print */
   8.273 +	(getattrfunc) ext2_fs_getattr, 	/* tp_getattr */
   8.274 +	0,				/* tp_setattr */
   8.275 +	0,				/* tp_compare */
   8.276 +	0,				/* tp_repr */
   8.277 +	0,				/* tp_as_number */
   8.278 +	0,	 			/* tp_as_sequence */
   8.279 +	0,				/* tp_as_mapping */
   8.280 +	0,           			/* tp_hash */
   8.281 +	0,                		/* tp_call */
   8.282 +	0,                    		/* tp_str */
   8.283 +	0,				/* tp_getattro */
   8.284 +	0,				/* tp_setattro */
   8.285 +	0,				/* tp_as_buffer */
   8.286 +	0L,	       			/* tp_flags */
   8.287 +	Ext2FsType__doc__,
   8.288 +	PY_PAD
   8.289 +};
   8.290 +
   8.291 +static PyObject *
   8.292 +ext2_fs_new(PyObject *o, PyObject *args, PyObject *kwargs) 
   8.293 +{
   8.294 +    static char *kwlist[] = { "name", "flags", "superblock", 
   8.295 +                              "block_size", NULL };
   8.296 +    char * name;
   8.297 +    int flags = 0, superblock = 0;
   8.298 +    unsigned int block_size = 0;
   8.299 +    Ext2Fs *pfs;
   8.300 +
   8.301 +    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, 
   8.302 +                                     &name, &flags, &superblock, &block_size))
   8.303 +        return NULL;
   8.304 +
   8.305 +    pfs = (Ext2Fs *) PyObject_NEW(Ext2Fs, &Ext2FsType);
   8.306 +    if (pfs == NULL)
   8.307 +        return NULL;
   8.308 +    pfs->fs = NULL;
   8.309 +
   8.310 +    if (!ext2_fs_open(pfs, 
   8.311 +                      Py_BuildValue("siii", name, flags, superblock, block_size),
   8.312 +                      NULL))
   8.313 +        return NULL;
   8.314 +
   8.315 +    return (PyObject *)pfs;
   8.316 +}
   8.317 +
   8.318 +
   8.319 +static struct PyMethodDef Ext2ModuleMethods[] = {
   8.320 +    { "Ext2Fs", (PyCFunction) ext2_fs_new, METH_VARARGS|METH_KEYWORDS, NULL },
   8.321 +    { NULL, NULL, 0, NULL }
   8.322 +};
   8.323 +
   8.324 +
   8.325 +void init_pyext2(void) {
   8.326 +    PyObject *m, *d;
   8.327 +
   8.328 +    m = Py_InitModule("_pyext2", Ext2ModuleMethods);
   8.329 +    d = PyModule_GetDict(m);
   8.330 +
   8.331 +    /*    o = PyObject_NEW(PyObject, yExt2FsConstructorType);
   8.332 +    PyDict_SetItemString(d, "PyExt2Fs", o);
   8.333 +    Py_DECREF(o);*/
   8.334 +                      
   8.335 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/tools/pygrub/src/fsys/ext2/test.py	Thu Apr 28 12:27:47 2005 +0000
     9.3 @@ -0,0 +1,15 @@
     9.4 +#!/usr/bin/python
     9.5 +
     9.6 +
     9.7 +import _pyext2
     9.8 +import struct, os, sys
     9.9 +
    9.10 +fs = _pyext2.Ext2Fs("test.img")
    9.11 +
    9.12 +f = fs.open_file("/boot/vmlinuz-2.6.11-1.1177_FC4")
    9.13 +buf = f.read()
    9.14 +o = open("vmlinuz", "wb+")
    9.15 +o.write(buf)
    9.16 +o.close()
    9.17 +
    9.18 +f.close()
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/tools/pygrub/src/pygrub	Thu Apr 28 12:27:47 2005 +0000
    10.3 @@ -0,0 +1,270 @@
    10.4 +#!/usr/bin/python
    10.5 +#
    10.6 +# pygrub - simple python-based bootloader for Xen
    10.7 +#
    10.8 +# Copyright 2005 Red Hat, Inc.
    10.9 +# Jeremy Katz <katzj@redhat.com>
   10.10 +#
   10.11 +# This software may be freely redistributed under the terms of the GNU
   10.12 +# general public license.
   10.13 +#
   10.14 +# You should have received a copy of the GNU General Public License
   10.15 +# along with this program; if not, write to the Free Software
   10.16 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   10.17 +#
   10.18 +
   10.19 +import os, sys, string, struct, tempfile
   10.20 +import logging
   10.21 +
   10.22 +import curses, _curses, curses.wrapper
   10.23 +import getopt
   10.24 +
   10.25 +import grub.GrubConf
   10.26 +import grub.fsys
   10.27 +
   10.28 +PYGRUB_VER = 0.02
   10.29 +
   10.30 +
   10.31 +def draw_window():
   10.32 +    stdscr = curses.initscr()
   10.33 +    curses.use_default_colors()
   10.34 +    try:
   10.35 +        curses.curs_set(0)
   10.36 +    except _curses.error:
   10.37 +        pass
   10.38 +
   10.39 +    stdscr.addstr(1, 4, "pyGRUB  version %s" %(PYGRUB_VER,))
   10.40 +
   10.41 +    win = curses.newwin(10, 74, 2, 1)
   10.42 +    win.box()
   10.43 +    win.refresh()
   10.44 +
   10.45 +    stdscr.addstr(12, 5, "Use the U and D keys to select which entry is highlighted.")
   10.46 +    stdscr.addstr(13, 5, "Press enter to boot the selected OS. 'e' to edit the")
   10.47 +    stdscr.addstr(14, 5, "commands before booting, 'a' to modify the kernel arguments ")
   10.48 +    stdscr.addstr(15, 5, "before booting, or 'c' for a command line.")
   10.49 +    stdscr.addch(12, 13, curses.ACS_UARROW)
   10.50 +    stdscr.addch(12, 19, curses.ACS_DARROW)
   10.51 +    (y, x) = stdscr.getmaxyx()
   10.52 +    stdscr.move(y - 1, x - 1)
   10.53 +
   10.54 +    stdscr.refresh()
   10.55 +    return (stdscr, win)
   10.56 +
   10.57 +def fill_entries(win, cfg, selected):
   10.58 +    y = 0
   10.59 +
   10.60 +    for i in cfg.images:
   10.61 +        if (0, y) > win.getmaxyx():
   10.62 +            break
   10.63 +        if y == selected:
   10.64 +            attr = curses.A_REVERSE
   10.65 +        else:
   10.66 +            attr = 0
   10.67 +        win.addstr(y + 1, 2, i.title.ljust(70), attr)
   10.68 +        y += 1
   10.69 +    win.refresh()
   10.70 +
   10.71 +def select(win, line):
   10.72 +    win.attron(curses.A_REVERSE)
   10.73 +    win.redrawln(line + 1, 1)
   10.74 +    win.refresh()
   10.75 +
   10.76 +def is_disk_image(file):
   10.77 +    fd = os.open(file, os.O_RDONLY)
   10.78 +    buf = os.read(fd, 512)
   10.79 +    os.close(fd)
   10.80 +
   10.81 +    if len(buf) >= 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaaff):
   10.82 +        return True
   10.83 +    return False
   10.84 +    
   10.85 +
   10.86 +def get_config(fn):
   10.87 +    if not os.access(fn, os.R_OK):
   10.88 +        raise RuntimeError, "Unable to access %s" %(fn,)
   10.89 +
   10.90 +    cf = grub.GrubConf.GrubConfigFile()
   10.91 +
   10.92 +    if is_disk_image(fn):
   10.93 +        raise RuntimeError, "appears to be a full disk image... unable to handle this yet"
   10.94 +
   10.95 +    # open the image and read the grub config
   10.96 +    fs = None
   10.97 +    for fstype in grub.fsys.fstypes.values():
   10.98 +        if fstype.sniff_magic(fn):
   10.99 +            fs = fstype.open_fs(fn)
  10.100 +            break
  10.101 +
  10.102 +    if fs is not None:
  10.103 +        f = fs.open_file("/boot/grub/grub.conf")
  10.104 +        buf = f.read()
  10.105 +        f.close()
  10.106 +        fs.close()
  10.107 +        # then parse the grub config
  10.108 +        cf.parse(buf)
  10.109 +    else:
  10.110 +        # set the config file and parse it
  10.111 +        cf.filename = fn
  10.112 +        cf.parse()
  10.113 +    
  10.114 +    return cf
  10.115 +
  10.116 +def get_entry_idx(cf, entry):
  10.117 +    # first, see if the given entry is numeric
  10.118 +    try:
  10.119 +        idx = string.atoi(entry)
  10.120 +        return idx
  10.121 +    except ValueError:
  10.122 +        pass
  10.123 +
  10.124 +    # it's not, now check the labels for a match
  10.125 +    for i in range(len(cf.images)):
  10.126 +        if entry == cf.images[i].title:
  10.127 +            return i
  10.128 +
  10.129 +    return None
  10.130 +
  10.131 +def main(cf = None):
  10.132 +    mytime = 0
  10.133 +
  10.134 +    (stdscr, win) = draw_window()
  10.135 +    stdscr.timeout(1000)
  10.136 +    selected = cf.default
  10.137 +    
  10.138 +    while (mytime < int(cf.timeout)):
  10.139 +        if cf.timeout != -1 and mytime != -1: 
  10.140 +            stdscr.addstr(20, 5, "Will boot selected entry in %2d seconds"
  10.141 +                          %(int(cf.timeout) - mytime))
  10.142 +        else:
  10.143 +            stdscr.addstr(20, 5, " " * 80)
  10.144 +            
  10.145 +        fill_entries(win, cf, selected)
  10.146 +        c = stdscr.getch()
  10.147 +        if mytime != -1:
  10.148 +            mytime += 1
  10.149 +#        if c == ord('q'):
  10.150 +#            selected = -1
  10.151 +#            break
  10.152 +        elif c == ord('c'):
  10.153 +            # FIXME: needs to go to command line mode
  10.154 +            continue
  10.155 +        elif c == ord('a'):
  10.156 +            # FIXME: needs to go to append mode
  10.157 +            continue
  10.158 +        elif c == ord('e'):
  10.159 +            # FIXME: needs to go to edit mode
  10.160 +            continue
  10.161 +        elif c in (curses.KEY_ENTER, ord('\n'), ord('\r')):
  10.162 +            break
  10.163 +        elif c == curses.KEY_UP:
  10.164 +            mytime = -1
  10.165 +            selected -= 1
  10.166 +        elif c == curses.KEY_DOWN:
  10.167 +            mytime = -1
  10.168 +            selected += 1
  10.169 +        else:
  10.170 +            pass
  10.171 +
  10.172 +        # bound at the top and bottom
  10.173 +        if selected < 0:
  10.174 +            selected = 0
  10.175 +        elif selected >= len(cf.images):
  10.176 +            selected = len(cf.images) - 1
  10.177 +
  10.178 +    if selected >= 0:
  10.179 +        return selected
  10.180 +
  10.181 +if __name__ == "__main__":
  10.182 +    sel = None
  10.183 +    
  10.184 +    def run_main(scr, *args):
  10.185 +        global sel
  10.186 +        sel = main(cf)
  10.187 +
  10.188 +    def usage():
  10.189 +        print >> sys.stderr, "Usage: %s [-q|--quiet] [--output=] [--entry=] <image>" %(sys.argv[0],)
  10.190 +
  10.191 +    try:
  10.192 +        opts, args = getopt.gnu_getopt(sys.argv[1:], 'qh::',
  10.193 +                                   ["quiet", "help", "output=", "entry="])
  10.194 +    except getopt.GetoptError:
  10.195 +        usage()
  10.196 +        sys.exit(1)
  10.197 +
  10.198 +    if len(args) < 1:
  10.199 +        usage()
  10.200 +        sys.exit(1)
  10.201 +    file = args[0]
  10.202 +        
  10.203 +    output = None
  10.204 +    entry = None
  10.205 +    interactive = True
  10.206 +    for o, a in opts:
  10.207 +        if o in ("-q", "--quiet"):
  10.208 +            interactive = False
  10.209 +        elif o in ("-h", "--help"):
  10.210 +            usage()
  10.211 +            sys.exit()
  10.212 +        elif o in ("--output",):
  10.213 +            output = a
  10.214 +        elif o in ("--entry",):
  10.215 +            entry = a
  10.216 +            # specifying the entry to boot implies non-interactive
  10.217 +            interactive = False
  10.218 +
  10.219 +    if output is None or output == "-":
  10.220 +        fd = sys.stdout.fileno()
  10.221 +    else:
  10.222 +        fd = os.open(output, os.O_WRONLY)
  10.223 +
  10.224 +    cf = get_config(file)
  10.225 +    if interactive:
  10.226 +        curses.wrapper(run_main)
  10.227 +    else:
  10.228 +        sel = cf.default
  10.229 +
  10.230 +    # set the entry to boot as requested
  10.231 +    if entry is not None:
  10.232 +        idx = get_entry_idx(cf, entry)
  10.233 +        if idx is not None and idx > 0 and idx < len(cf.images):
  10.234 +            sel = idx
  10.235 +
  10.236 +    img = cf.images[sel]
  10.237 +    print "Going to boot %s" %(img.title)
  10.238 +    print "  kernel: %s" %(img.kernel[1],)
  10.239 +    if img.initrd:
  10.240 +        print "  initrd: %s" %(img.initrd[1],)
  10.241 +
  10.242 +    if is_disk_image(file):
  10.243 +        raise RuntimeError, "unable to handle full disk images yet"
  10.244 +
  10.245 +    # read the kernel and initrd onto the hostfs
  10.246 +    fs = None
  10.247 +    for fstype in grub.fsys.fstypes.values():
  10.248 +        if fstype.sniff_magic(file):
  10.249 +            fs = fstype.open_fs(file)
  10.250 +            break
  10.251 +
  10.252 +    if fs is None:
  10.253 +        raise RuntimeError, "Unable to open filesystem"
  10.254 +
  10.255 +    kernel = fs.open_file(img.kernel[1],).read()
  10.256 +    (tfd, fn) = tempfile.mkstemp(prefix="vmlinuz.")
  10.257 +    os.write(tfd, kernel)
  10.258 +    os.close(tfd)
  10.259 +    sxp = "linux (kernel %s)" %(fn,)
  10.260 +
  10.261 +    if img.initrd:
  10.262 +        initrd = fs.open_file(img.initrd[1],).read()
  10.263 +        (tfd, fn) = tempfile.mkstemp(prefix="initrd.")
  10.264 +        os.write(tfd, initrd)
  10.265 +        os.close(tfd)
  10.266 +        sxp += "(ramdisk %s)" %(fn,)
  10.267 +    else:
  10.268 +        initrd = None
  10.269 +    sxp += "(args '%s')" %(img.args,)
  10.270 +
  10.271 +    sys.stdout.flush()
  10.272 +    os.write(fd, sxp)
  10.273 +    
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/tools/python/xen/xend/XendBootloader.py	Thu Apr 28 12:27:47 2005 +0000
    11.3 @@ -0,0 +1,94 @@
    11.4 +#
    11.5 +# XendBootloader.py - Framework to run a boot loader for picking the kernel
    11.6 +#
    11.7 +# Copyright 2005 Red Hat, Inc.
    11.8 +# Jeremy Katz <katzj@xxxxxxxxxx>
    11.9 +#
   11.10 +# This software may be freely redistributed under the terms of the GNU
   11.11 +# general public license.
   11.12 +#
   11.13 +# You should have received a copy of the GNU General Public License
   11.14 +# along with this program; if not, write to the Free Software
   11.15 +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   11.16 +#
   11.17 +
   11.18 +import os, sys, select
   11.19 +import sxp
   11.20 +
   11.21 +from XendLogging import log
   11.22 +from XendError import VmError
   11.23 +
   11.24 +BL_FIFO = "/var/lib/xen/xenbl"
   11.25 +
   11.26 +def bootloader(blexec, disk, quiet = 0, vcpus = None, entry = None):
   11.27 +    """Run the boot loader executable on the given disk and return a
   11.28 +    config image.
   11.29 +    @param blexec  Binary to use as the boot loader
   11.30 +    @param disk Disk to run the boot loader on.
   11.31 +    @param quiet Run in non-interactive mode, just booting the default.
   11.32 +    @param vcpus Number of vcpus for the domain.
   11.33 +    @param entry Default entry to boot."""
   11.34 +    
   11.35 +    if not os.access(blexec, os.X_OK):
   11.36 +        msg = "Bootloader isn't executable"
   11.37 +        log.error(msg)
   11.38 +        raise VmError(msg)
   11.39 +    if not os.access(disk, os.R_OK):
   11.40 +        msg = "Disk isn't accessible"
   11.41 +        log.error(msg)
   11.42 +        raise VmError(msg)
   11.43 +
   11.44 +    os.mkfifo(BL_FIFO, 0600)
   11.45 +
   11.46 +    child = os.fork()
   11.47 +    if (not child):
   11.48 +        args = [ blexec ]
   11.49 +        if quiet:
   11.50 +            args.append("-q")
   11.51 +        args.append("--output=%s" %(BL_FIFO,))
   11.52 +        if entry is not None:
   11.53 +            args.append("--entry=%s" %(entry,))
   11.54 +        args.append(disk)
   11.55 +
   11.56 +        try:
   11.57 +            os.execvp(args[0], args)
   11.58 +        except OSError, e:
   11.59 +            print e
   11.60 +            pass
   11.61 +        os._exit(1)
   11.62 +
   11.63 +    while 1:
   11.64 +        try:
   11.65 +            r = os.open(BL_FIFO, os.O_RDONLY)
   11.66 +        except OSError, e:
   11.67 +            if e.errno == 4:
   11.68 +                continue
   11.69 +        break
   11.70 +    ret = ""
   11.71 +    while 1:
   11.72 +        select.select([r], [], [])
   11.73 +        s = os.read(r, 1024)
   11.74 +        ret = ret + s
   11.75 +        if len(s) == 0:
   11.76 +            break
   11.77 +        
   11.78 +    (pid, status) = os.waitpid(child, 0)
   11.79 +    os.close(r)
   11.80 +    os.unlink(BL_FIFO)
   11.81 +
   11.82 +    if len(ret) == 0:
   11.83 +        msg = "Boot loader didn't return any data!"
   11.84 +        log.error(msg)
   11.85 +        raise VmError, msg
   11.86 +
   11.87 +    pin = sxp.Parser()
   11.88 +    pin.input(ret)
   11.89 +    pin.input_eof()
   11.90 +
   11.91 +    config_image = pin.val
   11.92 +    if vcpus and sxp.child_value(config_image, "vcpus") is None:
   11.93 +        config_image.append(['vcpus', vcpus])
   11.94 +
   11.95 +    config = ['image', config_image]
   11.96 +    return config
   11.97 +
    12.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Apr 28 08:59:31 2005 +0000
    12.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Thu Apr 28 12:27:47 2005 +0000
    12.3 @@ -16,11 +16,13 @@ import xen.lowlevel.xc; xc = xen.lowleve
    12.4  import xen.util.ip
    12.5  from xen.util.ip import _readline, _readlines
    12.6  from xen.xend.server import channel, controller
    12.7 +from xen.xend.server.blkif import blkdev_uname_to_file
    12.8  
    12.9  from server.channel import channelFactory
   12.10  import server.SrvDaemon; xend = server.SrvDaemon.instance()
   12.11  from server import messages
   12.12  
   12.13 +from xen.xend.XendBootloader import bootloader
   12.14  import sxp
   12.15  from XendLogging import log
   12.16  from XendError import VmError
   12.17 @@ -294,6 +296,7 @@ class XendDomainInfo:
   12.18          self.image_handler = None
   12.19          self.is_vmx = False
   12.20          self.vcpus = 1
   12.21 +        self.bootloader = None
   12.22  
   12.23      def setdom(self, dom):
   12.24          """Set the domain id.
   12.25 @@ -496,6 +499,7 @@ class XendDomainInfo:
   12.26              self.find_image_handler()
   12.27              self.init_domain()
   12.28              self.register_domain()
   12.29 +            self.configure_bootloader()
   12.30  
   12.31              # Create domain devices.
   12.32              self.configure_backends()
   12.33 @@ -674,6 +678,13 @@ class XendDomainInfo:
   12.34          memory = memory * 1024 + self.pgtable_size(memory)
   12.35          dom = xc.domain_create(dom= dom, mem_kb= memory,
   12.36                                 cpu= cpu, cpu_weight= cpu_weight)
   12.37 +        if self.bootloader:
   12.38 +            try:
   12.39 +                if kernel: os.unlink(kernel)
   12.40 +                if ramdisk: os.unlink(ramdisk)
   12.41 +            except OSError, e:
   12.42 +                log.warning('unable to unlink kernel/ramdisk: %s' %(e,))
   12.43 +
   12.44          if dom <= 0:
   12.45              raise VmError('Creating domain failed: name=%s memory=%d'
   12.46                            % (self.name, memory))
   12.47 @@ -854,6 +865,13 @@ class XendDomainInfo:
   12.48              self.config.remove(['device', dev_config])
   12.49          self.deleteDevice(type, dev.getId())
   12.50  
   12.51 +    def configure_bootloader(self):
   12.52 +        """Configure boot loader.
   12.53 +        """
   12.54 +        bl = sxp.child_value(self.config, "bootloader")
   12.55 +        if bl is not None:
   12.56 +            self.bootloader = bl
   12.57 +
   12.58      def configure_console(self):
   12.59          """Configure the vm console port.
   12.60          """
   12.61 @@ -931,10 +949,30 @@ class XendDomainInfo:
   12.62              self.state = STATE_VM_OK
   12.63              self.restart_check()
   12.64              self.restart_state = STATE_RESTART_BOOTING
   12.65 +            if self.bootloader:
   12.66 +                self.config = self.bootloader_config()
   12.67              self.construct(self.config)
   12.68          finally:
   12.69              self.restart_state = None
   12.70  
   12.71 +    def bootloader_config(self):
   12.72 +        # if we're restarting with a bootloader, we need to run it
   12.73 +        # FIXME: this assumes the disk is the first device and
   12.74 +        # that we're booting from the first disk
   12.75 +        blcfg = None
   12.76 +        # FIXME: this assumes that we want to use the first disk
   12.77 +        dev = sxp.child_value(self.config, "device")
   12.78 +        if dev:
   12.79 +            disk = sxp.child_value(dev, "uname")
   12.80 +            fn = blkdev_uname_to_file(disk)
   12.81 +            blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
   12.82 +        if blcfg is None:
   12.83 +            msg = "Had a bootloader specified, but can't find disk"
   12.84 +            log.error(msg)
   12.85 +            raise VmError(msg)
   12.86 +        config = sxp.merge(['vm', blconfig ], self.config)
   12.87 +        return config
   12.88 +
   12.89      def configure_backends(self):
   12.90          """Set configuration flags if the vm is a backend for netif or blkif.
   12.91          Configure the backends to use for vbd and vif if specified.
   12.92 @@ -1071,6 +1109,7 @@ def vm_image_linux(vm, image):
   12.93      if args:
   12.94          cmdline += " " + args
   12.95      ramdisk = sxp.child_value(image, "ramdisk", '')
   12.96 +    log.debug("creating linux domain with cmdline: %s" %(cmdline,))
   12.97      vm.create_domain("linux", kernel, ramdisk, cmdline)
   12.98      return vm
   12.99  
  12.100 @@ -1169,6 +1208,7 @@ add_config_handler('image',      vm_fiel
  12.101  add_config_handler('device',     vm_field_ignore)
  12.102  add_config_handler('backend',    vm_field_ignore)
  12.103  add_config_handler('vcpus',      vm_field_ignore)
  12.104 +add_config_handler('bootloader', vm_field_ignore)
  12.105  
  12.106  # Register other config handlers.
  12.107  add_config_handler('maxmem',     vm_field_maxmem)
    13.1 --- a/tools/python/xen/xend/server/blkif.py	Thu Apr 28 08:59:31 2005 +0000
    13.2 +++ b/tools/python/xen/xend/server/blkif.py	Thu Apr 28 12:27:47 2005 +0000
    13.3 @@ -71,6 +71,15 @@ def blkdev_segment(name):
    13.4                  'type'         : 'Disk' }
    13.5      return val
    13.6  
    13.7 +def blkdev_uname_to_file(uname):
    13.8 +    """Take a blkdev uname and return the corresponding filename."""
    13.9 +    fn = None
   13.10 +    if uname.find(":") != -1:
   13.11 +        (typ, fn) = uname.split(":")
   13.12 +        if typ == "phy" and not fn.startswith("/dev/"):
   13.13 +            fn = "/dev/%s" %(fn,)
   13.14 +    return fn
   13.15 +
   13.16  def mount_mode(name):
   13.17      mode = None
   13.18      name = expand_dev_name(name)
    14.1 --- a/tools/python/xen/xm/create.py	Thu Apr 28 08:59:31 2005 +0000
    14.2 +++ b/tools/python/xen/xm/create.py	Thu Apr 28 12:27:47 2005 +0000
    14.3 @@ -10,6 +10,8 @@ import socket
    14.4  from xen.xend import sxp
    14.5  from xen.xend import PrettyPrint
    14.6  from xen.xend.XendClient import server, XendError
    14.7 +from xen.xend.XendBootloader import bootloader
    14.8 +from xen.xend.server import blkif
    14.9  
   14.10  from xen.util import console_client
   14.11  
   14.12 @@ -94,6 +96,14 @@ gopts.var('name', val='NAME',
   14.13            fn=set_value, default=None,
   14.14            use="Domain name. Must be unique.")
   14.15  
   14.16 +gopts.var('bootloader', val='FILE',
   14.17 +          fn=set_value, default=None,
   14.18 +          use="Path to bootloader.")
   14.19 +
   14.20 +gopts.var('bootentry', val='NAME',
   14.21 +          fn=set_value, default=None,
   14.22 +          use="Entry to boot via boot loader")
   14.23 +
   14.24  gopts.var('kernel', val='FILE',
   14.25            fn=set_value, default=None,
   14.26            use="Path to kernel image.")
   14.27 @@ -252,7 +262,7 @@ def strip(pre, s):
   14.28      else:
   14.29          return s
   14.30  
   14.31 -def configure_image(config, vals):
   14.32 +def configure_image(opts, config, vals):
   14.33      """Create the image config.
   14.34      """
   14.35      config_image = [ vals.builder ]
   14.36 @@ -272,7 +282,7 @@ def configure_image(config, vals):
   14.37      config.append(['image', config_image ])
   14.38  
   14.39      
   14.40 -def configure_disks(config_devs, vals):
   14.41 +def configure_disks(opts, config_devs, vals):
   14.42      """Create the config for disks (virtual block devices).
   14.43      """
   14.44      for (uname, dev, mode, backend) in vals.disk:
   14.45 @@ -284,14 +294,14 @@ def configure_disks(config_devs, vals):
   14.46              config_vbd.append(['backend', backend])
   14.47          config_devs.append(['device', config_vbd])
   14.48  
   14.49 -def configure_pci(config_devs, vals):
   14.50 +def configure_pci(opts, config_devs, vals):
   14.51      """Create the config for pci devices.
   14.52      """
   14.53      for (bus, dev, func) in vals.pci:
   14.54          config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
   14.55          config_devs.append(['device', config_pci])
   14.56  
   14.57 -def configure_usb(config_devs, vals):
   14.58 +def configure_usb(opts, config_devs, vals):
   14.59      for path in vals.usb:
   14.60          config_usb = ['usb', ['path', path]]
   14.61          config_devs.append(['device', config_usb])
   14.62 @@ -315,7 +325,7 @@ def randomMAC():
   14.63              random.randint(0x00, 0xff) ]
   14.64      return ':'.join(map(lambda x: "%02x" % x, mac))
   14.65  
   14.66 -def configure_vifs(config_devs, vals):
   14.67 +def configure_vifs(opts, config_devs, vals):
   14.68      """Create the config for virtual network interfaces.
   14.69      """
   14.70      vifs = vals.vif
   14.71 @@ -357,7 +367,7 @@ def configure_vifs(config_devs, vals):
   14.72              config_vif.append(['ip', ip])
   14.73          config_devs.append(['device', config_vif])
   14.74  
   14.75 -def configure_vfr(config, vals):
   14.76 +def configure_vfr(opts, config, vals):
   14.77       if not vals.ipaddr: return
   14.78       config_vfr = ['vfr']
   14.79       idx = 0 # No way of saying which IP is for which vif?
   14.80 @@ -365,7 +375,7 @@ def configure_vfr(config, vals):
   14.81           config_vfr.append(['vif', ['id', idx], ['ip', ip]])
   14.82       config.append(config_vfr)
   14.83  
   14.84 -def configure_vmx(config_devs, vals):
   14.85 +def configure_vmx(opts, config_devs, vals):
   14.86      """Create the config for VMX devices.
   14.87      """
   14.88      memmap = vals.memmap
   14.89 @@ -375,7 +385,21 @@ def configure_vmx(config_devs, vals):
   14.90      config_devs.append(['device_model', device_model])
   14.91      config_devs.append(['device_config', device_config])
   14.92  
   14.93 -def make_config(vals):
   14.94 +def run_bootloader(opts, config, vals):
   14.95 +    if not os.access(vals.bootloader, os.X_OK):
   14.96 +        opts.err("Bootloader isn't executable")
   14.97 +    if len(vals.disk) < 1:
   14.98 +        opts.err("No disks configured and boot loader requested")
   14.99 +    (uname, dev, mode, backend) = vals.disk[0]
  14.100 +    file = blkif.blkdev_uname_to_file(uname)
  14.101 +
  14.102 +    blcfg = bootloader(vals.bootloader, file, not vals.console_autoconnect,
  14.103 +                       vals.vcpus, vals.blentry)
  14.104 +
  14.105 +    config.append(['bootloader', vals.bootloader])
  14.106 +    config.append(blcfg)
  14.107 +
  14.108 +def make_config(opts, vals):
  14.109      """Create the domain configuration.
  14.110      """
  14.111      
  14.112 @@ -396,15 +420,19 @@ def make_config(vals):
  14.113          config.append(['restart', vals.restart])
  14.114      if vals.console:
  14.115          config.append(['console', vals.console])
  14.116 -    
  14.117 -    configure_image(config, vals)
  14.118 +
  14.119 +    if vals.bootloader:
  14.120 +        run_bootloader(opts, config, vals)
  14.121 +    else:
  14.122 +        configure_image(opts, config, vals)
  14.123      config_devs = []
  14.124 -    configure_disks(config_devs, vals)
  14.125 -    configure_pci(config_devs, vals)
  14.126 -    configure_vifs(config_devs, vals)
  14.127 -    configure_usb(config_devs, vals)
  14.128 -    configure_vmx(config_devs, vals)
  14.129 +    configure_disks(opts, config_devs, vals)
  14.130 +    configure_pci(opts, config_devs, vals)
  14.131 +    configure_vifs(opts, config_devs, vals)
  14.132 +    configure_usb(opts, config_devs, vals)
  14.133 +    configure_vmx(opts, config_devs, vals)
  14.134      config += config_devs
  14.135 +
  14.136      return config
  14.137  
  14.138  def preprocess_disk(opts, vals):
  14.139 @@ -587,7 +615,8 @@ def main(argv):
  14.140          preprocess(opts, opts.vals)
  14.141          if not opts.getopt('name') and opts.getopt('defconfig'):
  14.142              opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
  14.143 -        config = make_config(opts.vals)
  14.144 +        config = make_config(opts, opts.vals)
  14.145 +
  14.146      if opts.vals.dryrun:
  14.147          PrettyPrint.prettyprint(config)
  14.148      else:
    15.1 --- a/tools/xfrd/xfrd.c	Thu Apr 28 08:59:31 2005 +0000
    15.2 +++ b/tools/xfrd/xfrd.c	Thu Apr 28 12:27:47 2005 +0000
    15.3 @@ -49,7 +49,7 @@
    15.4  #include "select.h"
    15.5  
    15.6  #define MODULE_NAME "XFRD"
    15.7 -
    15.8 +#define DEBUG 1
    15.9  #include "debug.h"
   15.10  
   15.11  /*
   15.12 @@ -1226,7 +1226,9 @@ int main(int argc, char *argv[]){
   15.13      int err = 0;
   15.14      int key = 0;
   15.15      int long_index = 0;
   15.16 +#ifndef DEBUG
   15.17      static const char * LOGFILE = "/var/log/xfrd.log";
   15.18 +#endif
   15.19  
   15.20  #ifndef DEBUG
   15.21      freopen(LOGFILE, "w+", stdout);