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

Re: [Xen-devel] [PATCH] Guest boot loader support [2/2]

To: Jeremy Katz <katzj@xxxxxxxxxx>
Subject: Re: [Xen-devel] [PATCH] Guest boot loader support [2/2]
From: Mike Wray <mike.wray@xxxxxxxxxx>
Date: Thu, 14 Apr 2005 13:28:47 +0100
Cc: Ian Pratt <m+Ian.Pratt@xxxxxxxxxxxx>, xen-devel@xxxxxxxxxxxxxxxxxxx
Delivery-date: Thu, 14 Apr 2005 17:26:34 +0000
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <1113448377.5078.51.camel@xxxxxxxxxxxxxx>
List-help: <mailto:xen-devel-request@lists.xensource.com?subject=help>
List-id: Xen developer discussion <xen-devel.lists.xensource.com>
List-post: <mailto:xen-devel@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/cgi-bin/mailman/listinfo/xen-devel>, <mailto:xen-devel-request@lists.xensource.com?subject=unsubscribe>
References: <1113448377.5078.51.camel@xxxxxxxxxxxxxx>
Sender: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mozilla Thunderbird 1.0.2 (X11/20050317)
Jeremy Katz wrote:
This adds pygrub, an implementation of a bootloader for domU.  It reads
from the guest filesystem (using libext2fs) and provides a grub-like
interface for selecting the kernel/initrd/kernel args for booting your
domU.

TODO list off the top of my head:
* Support filesystems other than ext[23]
* Support whole disk images and not just a partition image
* Implement command line editing/append mode
* Possibly the full command line stuff
* Password support
* Other missing important bits?

Even with that, it's still quite functional.

I may be wrong, but it looks like the code printing out the sxpr
is missing some brackets. See below (almost at the end).

Mike


Signed-off-by: Jeremy Katz <katzj@xxxxxxxxxx>

Jeremy


------------------------------------------------------------------------

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
# 2005/04/13 23:02:35-04:00 katzj@xxxxxxxxxxxxxx # Add pygrub, a simple boot loader for use to read a boot loader
#   config out of a domU's filesystem and then read kernels out as well.
#   Currently only has support for ext[23] via libext2fs, but it should
#   be easy to add other filesystems.
# # Still needs work to complete the interface and to support full disk
#   images instead of just partitions.
# # tools/pygrub/src/pygrub
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +255 -0
# # tools/pygrub/src/fsys/ext2/test.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +15 -0
# # tools/pygrub/src/fsys/ext2/ext2module.c
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +332 -0
# # tools/pygrub/src/fsys/ext2/__init__.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +38 -0
# # tools/pygrub/src/fsys/__init__.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +61 -0
# # tools/pygrub/src/GrubConf.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +229 -0
# # tools/pygrub/setup.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +25 -0
# # tools/pygrub/Makefile
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +18 -0
# # tools/pygrub/src/pygrub
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file /home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/pygrub
# # tools/pygrub/src/fsys/ext2/test.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file 
/home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/fsys/ext2/test.py
# # tools/pygrub/src/fsys/ext2/ext2module.c
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file 
/home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/fsys/ext2/ext2module.c
# # tools/pygrub/src/fsys/ext2/__init__.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file 
/home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/fsys/ext2/__init__.py
# # tools/pygrub/src/fsys/__init__.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file 
/home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/fsys/__init__.py
# # tools/pygrub/src/GrubConf.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file /home/katzj/cvs/xen/xen-pygrub/tools/pygrub/src/GrubConf.py
# # tools/pygrub/setup.py
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file /home/katzj/cvs/xen/xen-pygrub/tools/pygrub/setup.py
# # tools/pygrub/Makefile
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +0 -0
#   BitKeeper file /home/katzj/cvs/xen/xen-pygrub/tools/pygrub/Makefile
# # tools/Makefile
#   2005/04/13 23:02:33-04:00 katzj@xxxxxxxxxxxxxx +1 -0
#   Add pygrub subdirectory
# diff -Nru a/tools/Makefile b/tools/Makefile
--- a/tools/Makefile    2005-04-13 23:04:05 -04:00
+++ b/tools/Makefile    2005-04-13 23:04:05 -04:00
@@ -11,6 +11,7 @@
 SUBDIRS += xfrd
 SUBDIRS += xcs
 SUBDIRS += ioemu
+SUBDIRS += pygrub
.PHONY: all install clean check check_clean diff -Nru a/tools/pygrub/Makefile b/tools/pygrub/Makefile
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/Makefile     2005-04-13 23:04:05 -04:00
@@ -0,0 +1,18 @@
+
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+all: build
+build:
+       CFLAGS="$(CFLAGS)" python setup.py build
+
+ifndef XEN_PYTHON_NATIVE_INSTALL
+install: all
+       CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr"
+else
+install: all
+       CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
+endif
+
+clean:
+       rm -rf build *.pyc *.pyo *.o *.a *~
diff -Nru a/tools/pygrub/setup.py b/tools/pygrub/setup.py
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/setup.py     2005-04-13 23:04:05 -04:00
@@ -0,0 +1,25 @@
+from distutils.core import setup, Extension
+import os
+
+extra_compile_args  = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
+
+# in a perfect world, we'd figure out the fsys modules dynamically
+ext2 = Extension("grub.fsys.ext2._pyext2",
+                 extra_compile_args = extra_compile_args,
+                 libraries = ["ext2fs"],
+                 sources = ["src/fsys/ext2/ext2module.c"])
+
+setup(name='pygrub',
+      version='0.1',
+      description='Boot loader that looks a lot like grub for Xen',
+      author='Jeremy Katz',
+      author_email='katzj@xxxxxxxxxx',
+      license='GPL',
+      package_dir={'grub': 'src'},
+      scripts = ["src/pygrub"],
+      packages=['grub',
+                'grub.fsys',
+                'grub.fsys.ext2'],
+      ext_modules = [ext2]
+      )
+ diff -Nru a/tools/pygrub/src/GrubConf.py b/tools/pygrub/src/GrubConf.py
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/GrubConf.py      2005-04-13 23:04:05 -04:00
@@ -0,0 +1,229 @@
+#
+# GrubConf.py - Simple grub.conf parsing
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os, sys
+import logging
+
+def grub_split(s, maxsplit = -1):
+    """Split a grub option screen separated with either '=' or whitespace."""
+    eq = s.find('=')
+    if eq == -1:
+        return s.split(None, maxsplit)
+
+    # see which of a space or tab is first
+    sp = s.find(' ')
+    tab = s.find('\t')
+    if (tab != -1 and tab < sp) or (tab != -1 and sp == -1):
+        sp = tab
+
+    if eq != -1 and eq < sp or (eq != -1 and sp == -1):
+        return s.split('=', maxsplit)
+    else:
+        return s.split(None, maxsplit)
+
+def get_path(s):
+    """Returns a tuple of (GrubDiskPart, path) corresponding to string."""
+    if not s.startswith('('):
+        return (None, s)
+    idx = s.find(')')
+    if idx == -1:
+        raise ValueError, "Unable to find matching ')'"
+    d = s[:idx]
+    return (GrubDiskPart(d), s[idx + 1:])
+
+class GrubDiskPart(object):
+    def __init__(self, str):
+        if str.find(',') != -1:
+            (self.disk, self.part) = str.split(",", 2)
+        else:
+            self.disk = str
+            self.part = None
+
+    def __repr__(self):
+        if self.part is not None:
+            return "d%dp%d" %(self.disk, self.part)
+        else:
+            return "d%d" %(self,disk,)
+
+    def get_disk(self):
+        return self._disk
+    def set_disk(self, val):
+        val = val.replace("(", "").replace(")", "")
+        self._disk = int(val[2:])
+    disk = property(get_disk, set_disk)
+
+    def get_part(self):
+        return self._part
+    def set_part(self, val):
+        if val is None:
+            self._part = val
+            return
+        val = val.replace("(", "").replace(")", "")
+        self._part = int(val)
+    part = property(get_part, set_part)
+
+class GrubImage(object):
+    def __init__(self, lines):
+        self._root = self._initrd = self._kernel = self._args = None
+        for l in lines:
+            (com, arg) = grub_split(l, 1)
+
+            if self.commands.has_key(com):
+                if self.commands[com] is not None:
+                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
+                else:
+                    logging.info("Ignored image directive %s" %(com,))
+            else:
+                logging.warning("Unknown image directive %s" %(com,))
+
+    def __repr__(self):
+ return ("title: %s\n" + " root: %s\n"
+                "  kernel: %s\n"
+                "  args: %s\n"
+                "  initrd: %s" %(self.title, self.root, self.kernel,
+                                   self.args, self.initrd))
+
+    def set_root(self, val):
+        self._root = GrubDiskPart(val)
+    def get_root(self):
+        return self._root
+    root = property(get_root, set_root)
+
+    def set_kernel(self, val):
+        if val.find(" ") == -1:
+            self._kernel = get_path(val)
+            self._args = None
+            return
+        (kernel, args) = val.split(None, 1)
+        self._kernel = get_path(kernel)
+        self._args = args
+    def get_kernel(self):
+        return self._kernel
+    def get_args(self):
+        return self._args
+    kernel = property(get_kernel, set_kernel)
+    args = property(get_args)
+
+    def set_initrd(self, val):
+        self._initrd = get_path(val)
+    def get_initrd(self):
+        return self._initrd
+    initrd = property(get_initrd, set_initrd)
+
+    # set up command handlers
+    commands = { "title": "self.title",
+                 "root": "self.root",
+                 "rootnoverify": "self.root",
+                 "kernel": "self.kernel",
+                 "initrd": "self.initrd",
+                 "chainloader": None,
+                 "module": None}
+ +
+class GrubConfigFile(object):
+    def __init__(self, fn = None):
+        self.filename = fn
+        self.images = []
+        self.timeout = -1
+
+        if fn is not None:
+            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.images.append(GrubImage(img))
+                img = [l]
+                continue
+ + if len(img) > 0:
+                img.append(l)
+                continue
+
+            try:
+                (com, arg) = grub_split(l, 1)
+            except ValueError:
+                com = l
+                arg = ""
+
+            if self.commands.has_key(com):
+                if self.commands[com] is not None:
+                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
+                else:
+                    logging.info("Ignored directive %s" %(com,))
+            else:
+                logging.warning("Unknown directive %s" %(com,))
+ + if len(img) > 0:
+            self.images.append(GrubImage(img))
+
+    def _get_default(self):
+        return self._default
+    def _set_default(self, val):
+        if val == "saved":
+            self._default = -1
+        else:
+            self._default = int(val)
+
+        if self._default < 0:
+            raise ValueError, "default must be positive number"
+    default = property(_get_default, _set_default)
+
+    def set_splash(self, val):
+        self._splash = get_path(val)
+    def get_splash(self):
+        return self._splash
+    splash = property(get_splash, set_splash)
+
+    # set up command handlers
+    commands = { "default": "self.default",
+                 "timeout": "self.timeout",
+                 "fallback": "self.fallback",
+                 "hiddenmenu": "self.hiddenmenu",
+                 "splashimage": "self.splash",
+                 "password": "self.password" }
+    for c in ("bootp", "color", "device", "dhcp", "hide", "ifconfig",
+              "pager", "partnew", "parttype", "rarp", "serial",
+              "setkey", "terminal", "terminfo", "tftpserver", "unhide"):
+        commands[c] = None
+    del c
+
+
+if __name__ == "__main__":
+    if sys.argv < 2:
+        raise RuntimeError, "Need a grub.conf to read"
+    g = GrubConfigFile(sys.argv[1])
+    for i in g.images:
+        print i #, i.title, i.root, i.kernel, i.args, i.initrd
diff -Nru a/tools/pygrub/src/fsys/__init__.py 
b/tools/pygrub/src/fsys/__init__.py
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/fsys/__init__.py 2005-04-13 23:04:05 -04:00
@@ -0,0 +1,61 @@
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os
+import sys
+
+fstypes = {}
+
+def register_fstype(x):
+    if x.name in fstypes.keys():
+        return
+    fstypes[x.name] = x
+
+class FileSystemType(object):
+    """A simple representation for a file system that gives a fs name
+    and a method for sniffing a file to see if it's of the given fstype."""
+    def __init__(self):
+        self.name = ""
+
+    def sniff_magic(self, fn, offset = 0):
+        """Look at the filesystem at fn for the appropriate magic starting at
+        offset offset."""
+        raise RuntimeError, "sniff_magic not implemented"
+
+    def open_fs(self, fn, offset = 0):
+        """Open the given filesystem and return a filesystem object."""
+        raise RuntimeError, "open_fs not implemented"
+
+class FileSystem(object):
+    def open(self, name, flags = 0, block_size = 0):
+        """Open the fsys on name with given flags and block_size."""
+        raise RuntimeError, "open not implemented"
+
+    def close(self):
+        """Close the fsys."""
+        raise RuntimeError, "close not implemented"
+
+    def open_file(self, file, flags = None):
+        """Open the file 'name' with the given flags.  The returned object
+        should look similar to a native file object."""
+        raise RuntimeError, "open_file not implemented"
+ +
+
+mydir = sys.modules['grub.fsys'].__path__[0]
+for f in os.listdir(mydir):
+    if not os.path.isdir("%s/%s" %(mydir, f)):
+        continue
+    try:
+ exec "import grub.fsys.%s" %(f,) + except ImportError, e:
+        pass
diff -Nru a/tools/pygrub/src/fsys/ext2/__init__.py 
b/tools/pygrub/src/fsys/ext2/__init__.py
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/fsys/ext2/__init__.py    2005-04-13 23:04:05 -04:00
@@ -0,0 +1,38 @@
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+from grub.fsys import register_fstype, FileSystemType
+from _pyext2 import *
+
+import os, struct
+
+class Ext2FileSystemType(FileSystemType):
+    def __init__(self):
+        FileSystemType.__init__(self)
+        self.name = "ext2"
+
+    def sniff_magic(self, fn, offset = 0):
+        fd = os.open(fn, os.O_RDONLY)
+        os.lseek(fd, offset, 0)
+        buf = os.read(fd, 2048)
+ + if len(buf) > 1082 and \
+               struct.unpack("<H", buf[1080:1082]) == (0xef53,):
+            return True
+        return False
+
+    def open_fs(self, fn, offset = 0):
+        if not self.sniff_magic(fn, offset):
+            raise ValueError, "Not an ext2 filesystem"
+        return Ext2Fs(fn)
+
+register_fstype(Ext2FileSystemType())
+
diff -Nru a/tools/pygrub/src/fsys/ext2/ext2module.c 
b/tools/pygrub/src/fsys/ext2/ext2module.c
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/fsys/ext2/ext2module.c   2005-04-13 23:04:05 -04:00
@@ -0,0 +1,332 @@
+/*
+ * ext2module.c - simple python binding for libext2fs
+ *
+ * Copyright 2005 Red Hat, Inc.
+ * Jeremy Katz <katzj@xxxxxxxxxx>
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * general public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <Python.h>
+
+#include <ext2fs/ext2fs.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if (PYTHON_API_VERSION >= 1011)
+#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
+#else
+#define PY_PAD 0L,0L,0L,0L
+#endif
+
+
+/* global error object */
+PyObject *Ext2Error;
+
+typedef struct _Ext2Fs Ext2Fs;
+struct _Ext2Fs {
+    PyObject_HEAD;
+    ext2_filsys fs;
+};
+
+typedef struct _Ext2File Ext2File;
+struct _Ext2File {
+    PyObject_HEAD;
+    ext2_file_t file;
+};
+
+/* ext2 file object */
+
+static PyObject *
+ext2_file_close (Ext2File *file, PyObject *args)
+{
+    if (file->file != NULL)
+        ext2fs_file_close(file->file);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_file_read (Ext2File *file, PyObject *args)
+{
+    int err, size = 0;
+    size_t n, total = 0;
+    PyObject * buffer = NULL;
+
+    if (file->file == NULL) {
+        PyErr_SetString(PyExc_ValueError, "Cannot read from closed file");
+        return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "|i", &size))
+        return NULL;
+
+    buffer = PyString_FromStringAndSize((char *) NULL, (size) ? size : 4096);
+    if (buffer == NULL)
+        return buffer;
+ + while (1) { + err = ext2fs_file_read(file->file, PyString_AS_STRING(buffer) + total, + (size) ? size : 4096, &n);
+        if (err) {
+            if (buffer != NULL) { Py_DECREF(buffer); }
+            Py_DECREF(buffer);
+            PyErr_SetString(PyExc_ValueError, "read error");
+            return NULL;
+        }
+
+        total += n;
+        if (n == 0)
+            break;
+
+        if (size && size == total)
+            break;
+
+        if (!size) {
+            _PyString_Resize(&buffer, total + 4096);
+        }
+    }
+
+    _PyString_Resize(&buffer, total);
+    return buffer;
+}
+
+static void
+ext2_file_dealloc (Ext2File * file)
+{
+    if (file->file != NULL)
+        ext2fs_file_close(file->file);
+    PyMem_DEL(file);
+}
+
+static struct PyMethodDef Ext2FileMethods[] = {
+        { "close",
+          (PyCFunction) ext2_file_close,
+          METH_VARARGS, NULL },
+        { "read",
+          (PyCFunction) ext2_file_read,
+          METH_VARARGS, NULL },
+       { NULL, NULL, 0, NULL } 
+};
+
+static PyObject *
+ext2_file_getattr (Ext2File * file, char * name)
+{
+        return Py_FindMethod (Ext2FileMethods, (PyObject *) file, name);
+}
+
+static char Ext2FileType__doc__[] = "This is the ext2 filesystem object";
+PyTypeObject Ext2FileType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                              /* ob_size */
+       "Ext2File",                   /* tp_name */
+       sizeof(Ext2File),               /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) ext2_file_dealloc,         /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) ext2_file_getattr,        /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+       0,                              /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       0,                              /* tp_getattro */
+       0,                              /* tp_setattro */
+       0,                              /* tp_as_buffer */
+       0L,                             /* tp_flags */
+       Ext2FileType__doc__,
+       PY_PAD
+};
+
+static PyObject *
+ext2_file_open (Ext2Fs *fs, char * name, int flags)
+{
+    int err;
+    ext2_file_t f;
+    ext2_ino_t ino;
+    Ext2File * file;
+
+    file = (Ext2File *) PyObject_NEW(Ext2File, &Ext2FileType);
+    file->file = NULL;
+
+    err = ext2fs_namei_follow(fs->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, 
&ino);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    err = ext2fs_file_open(fs->fs, ino, flags, &f);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    file->file = f;
+    return (PyObject *) file;
+}
+
+/* ext2fs object */
+
+static PyObject *
+ext2_fs_close (Ext2Fs *fs, PyObject *args)
+{
+    if (fs->fs != NULL)
+        ext2fs_close(fs->fs);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_fs_open (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = { "name", "flags", "superblock", + "block_size", NULL };
+    char * name;
+    int flags = 0, superblock = 0, err;
+    unsigned int block_size = 0;
+    ext2_filsys efs;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, + &name, &flags, &superblock, &block_size))
+                                     return NULL;
+
+    if (fs->fs != NULL) {
+        PyErr_SetString(PyExc_ValueError, "already have an fs object");
+        return NULL;
+    }
+
+ err = ext2fs_open(name, flags, superblock, block_size, + unix_io_manager, &efs);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    fs->fs = efs;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_fs_open_file (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = { "name", "flags", NULL };
+    char * name;
+    int flags = 0;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist, + &name, &flags))
+                                     return NULL;
+
+    return ext2_file_open(fs, name, flags);
+}
+
+static void
+ext2_fs_dealloc (Ext2Fs * fs)
+{
+    if (fs->fs != NULL)
+        ext2fs_close(fs->fs);
+    PyMem_DEL(fs);
+}
+
+static struct PyMethodDef Ext2FsMethods[] = {
+        { "close",
+          (PyCFunction) ext2_fs_close,
+          METH_VARARGS, NULL },
+        { "open",
+          (PyCFunction) ext2_fs_open,
+          METH_VARARGS|METH_KEYWORDS, NULL },
+        { "open_file",
+          (PyCFunction) ext2_fs_open_file,
+          METH_VARARGS|METH_KEYWORDS, NULL },
+       { NULL, NULL, 0, NULL } 
+};
+
+static PyObject *
+ext2_fs_getattr (Ext2Fs * fs, char * name)
+{
+        return Py_FindMethod (Ext2FsMethods, (PyObject *) fs, name);
+}
+
+static char Ext2FsType__doc__[] = "This is the ext2 filesystem object";
+PyTypeObject Ext2FsType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                              /* ob_size */
+       "Ext2Fs",                     /* tp_name */
+       sizeof(Ext2Fs),         /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) ext2_fs_dealloc,   /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) ext2_fs_getattr,  /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+       0,                              /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       0,                              /* tp_getattro */
+       0,                              /* tp_setattro */
+       0,                              /* tp_as_buffer */
+       0L,                             /* tp_flags */
+       Ext2FsType__doc__,
+       PY_PAD
+};
+
+static PyObject *
+ext2_fs_new(PyObject *o, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "name", "flags", "superblock", + "block_size", NULL };
+    char * name;
+    int flags = 0, superblock = 0;
+    unsigned int block_size = 0;
+    Ext2Fs *pfs;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, + &name, &flags, &superblock, &block_size))
+        return NULL;
+
+    pfs = (Ext2Fs *) PyObject_NEW(Ext2Fs, &Ext2FsType);
+    if (pfs == NULL)
+        return NULL;
+    pfs->fs = NULL;
+
+ if (!ext2_fs_open(pfs, + Py_BuildValue("siii", name, flags, superblock, block_size),
+                      NULL))
+        return NULL;
+
+    return (PyObject *)pfs;
+}
+
+
+static struct PyMethodDef Ext2ModuleMethods[] = {
+    { "Ext2Fs", (PyCFunction) ext2_fs_new, METH_VARARGS|METH_KEYWORDS, NULL },
+    { NULL, NULL, 0, NULL }
+};
+
+
+void init_pyext2(void) {
+    PyObject *m, *d;
+
+    m = Py_InitModule("_pyext2", Ext2ModuleMethods);
+    d = PyModule_GetDict(m);
+
+    /*    o = PyObject_NEW(PyObject, yExt2FsConstructorType);
+    PyDict_SetItemString(d, "PyExt2Fs", o);
+    Py_DECREF(o);*/
+ +}
diff -Nru a/tools/pygrub/src/fsys/ext2/test.py 
b/tools/pygrub/src/fsys/ext2/test.py
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/fsys/ext2/test.py        2005-04-13 23:04:05 -04:00
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+
+
+import _pyext2
+import struct, os, sys
+
+fs = _pyext2.Ext2Fs("test.img")
+
+f = fs.open_file("/boot/vmlinuz-2.6.11-1.1177_FC4")
+buf = f.read()
+o = open("vmlinuz", "wb+")
+o.write(buf)
+o.close()
+
+f.close()
diff -Nru a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
--- /dev/null   Wed Dec 31 16:00:00 196900
+++ b/tools/pygrub/src/pygrub   2005-04-13 23:04:05 -04:00
@@ -0,0 +1,255 @@
+#!/usr/bin/python
+#
+# pygrub - simple python-based bootloader for Xen
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os, sys, struct, tempfile
+import logging
+
+import curses, _curses, curses.wrapper
+import getopt
+
+import grub.GrubConf
+import grub.fsys
+
+PYGRUB_VER = 0.01
+
+
+def draw_window():
+    stdscr = curses.initscr()
+    curses.use_default_colors()
+    try:
+        curses.curs_set(0)
+    except _curses.error:
+        pass
+
+    stdscr.addstr(1, 4, "pyGRUB  version %s" %(PYGRUB_VER,))
+
+    win = curses.newwin(10, 74, 2, 1)
+    win.box()
+    win.refresh()
+
+    stdscr.addstr(12, 5, "Use the U and D keys to select which entry is 
highlighted.")
+    stdscr.addstr(13, 5, "Press enter to boot the selected OS. 'e' to edit 
the")
+    stdscr.addstr(14, 5, "commands before booting, 'a' to modify the kernel 
arguments ")
+    stdscr.addstr(15, 5, "before booting, or 'c' for a command line.")
+    stdscr.addch(12, 13, curses.ACS_UARROW)
+    stdscr.addch(12, 19, curses.ACS_DARROW)
+    (y, x) = stdscr.getmaxyx()
+    stdscr.move(y - 1, x - 1)
+
+    stdscr.refresh()
+    return (stdscr, win)
+
+def fill_entries(win, cfg, selected):
+    y = 0
+
+    for i in cfg.images:
+        if (0, y) > win.getmaxyx():
+            break
+        if y == selected:
+            attr = curses.A_REVERSE
+        else:
+            attr = 0
+        win.addstr(y + 1, 2, i.title.ljust(70), attr)
+        y += 1
+    win.refresh()
+
+def select(win, line):
+    win.attron(curses.A_REVERSE)
+    win.redrawln(line + 1, 1)
+    win.refresh()
+
+def is_ext2_image(file):
+    fd = os.open(file, os.O_RDONLY)
+    buf = os.read(fd, 2048)
+    os.close(fd)
+
+    if len(buf) > 1082 and struct.unpack("<H", buf[1080:1082]) == (0xef53,):
+        return True
+    return False
+
+def is_disk_image(file):
+    fd = os.open(file, os.O_RDONLY)
+    buf = os.read(fd, 512)
+    os.close(fd)
+
+    if len(buf) >= 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaaff):
+        return True
+    return False
+ +
+def get_config(fn):
+    if not os.access(fn, os.R_OK):
+        raise RuntimeError, "Unable to access %s" %(fn,)
+
+    cf = grub.GrubConf.GrubConfigFile()
+
+    if is_disk_image(fn):
+        raise RuntimeError, "appears to be a full disk image... unable to handle 
this yet"
+
+    # open the image and read the grub config
+    fs = None
+    for fstype in grub.fsys.fstypes.values():
+        if fstype.sniff_magic(fn):
+            fs = fstype.open_fs(fn)
+            break
+
+    if fs is not None:
+        f = fs.open_file("/boot/grub/grub.conf")
+        buf = f.read()
+        f.close()
+        fs.close()
+        # then parse the grub config
+        cf.parse(buf)
+    else:
+        # set the config file and parse it
+        cf.filename = fn
+        cf.parse()
+ + return cf + +
+def main(cf = None):
+    mytime = 0
+
+    (stdscr, win) = draw_window()
+    stdscr.timeout(1000)
+    selected = cf.default
+ + while (mytime < int(cf.timeout)): + if cf.timeout != -1 and mytime != -1: + stdscr.addstr(20, 5, "Will boot selected entry in %2d seconds"
+                          %(int(cf.timeout) - mytime))
+        else:
+            stdscr.addstr(20, 5, " " * 80)
+ + fill_entries(win, cf, selected)
+        c = stdscr.getch()
+        if mytime != -1:
+            mytime += 1
+        if c == ord('q'):
+            selected = -1
+            break
+        elif c == ord('c'):
+            # FIXME: needs to go to command line mode
+            continue
+        elif c == ord('a'):
+            # FIXME: needs to go to append mode
+            continue
+        elif c == ord('e'):
+            # FIXME: needs to go to edit mode
+            continue
+        elif c in (curses.KEY_ENTER, ord('\n'), ord('\r')):
+            break
+        elif c == curses.KEY_UP:
+            mytime = -1
+            selected -= 1
+        elif c == curses.KEY_DOWN:
+            mytime = -1
+            selected += 1
+        else:
+            pass
+
+        # bound at the top and bottom
+        if selected < 0:
+            selected = 0
+        elif selected >= len(cf.images):
+            selected = len(cf.images) - 1
+
+    if selected >= 0:
+        return selected
+
+if __name__ == "__main__":
+    sel = None
+ + def run_main(scr, *args):
+        global sel
+        sel = main(cf)
+
+    def usage():
+        print "Usage: %s [-q|--quiet] [-o|--output=] <image>" %(sys.argv[0],)
+
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], 'qh:o:',
+                                   ["quiet", "help", "output"])
+    except getopt.GetoptError:
+        usage()
+        sys.exit(1)
+
+    if len(args) < 1:
+        usage()
+        sys.exit(1)
+    print args
+    file = args[0]
+ + output = None
+    interactive = True
+    for o, a in opts:
+        if o in ("-q", "--quiet"):
+            interactive = False
+        elif o in ("-h", "--help"):
+            usage()
+            sys.exit()
+        elif o in ("-o", "--output"):
+            output = a
+
+    if output is None or output == "-":
+        fd = sys.stdout.fileno()
+    else:
+        fd = os.open(output, os.O_WRONLY)
+
+    cf = get_config(file)
+    if interactive:
+        curses.wrapper(run_main)
+    else:
+        sel = cf.default
+
+    img = cf.images[sel]
+    print "Going to boot %s" %(img.title)
+    print "  kernel: %s" %(img.kernel[1],)
+    if img.initrd:
+        print "  initrd: %s" %(img.initrd[1],)
+
+    if is_disk_image(file):
+        raise RuntimeError, "unable to handle full disk images yet"
+
+    # read the kernel and initrd onto the hostfs
+    fs = None
+    for fstype in grub.fsys.fstypes.values():
+        if fstype.sniff_magic(file):
+            fs = fstype.open_fs(file)
+            break
+
+    if fs is None:
+        raise RuntimeError, "Unable to open filesystem"
+
+    kernel = fs.open_file(img.kernel[1],).read()
+    (tfd, fn) = tempfile.mkstemp(prefix="vmlinuz.")
+    os.write(tfd, kernel)
+    os.close(tfd)
+    sxp = "linux (kernel %s)" %(fn,)
+
+    if img.initrd:
+        initrd = fs.open_file(img.initrd[1],).read()
+        (tfd, fn) = tempfile.mkstemp(prefix="initrd.")
+        os.write(tfd, initrd)
+        os.close(tfd)
+        sxp += "(ramdisk %s)" %(fn,)
+    else:
+        initrd = None
+    sxp += "(args '%s')" %(img.args,)

It looks like the code above is missing some brackets in the output:
shouldn't it be writing "(linux ..." instead of "linux ...",
and adding a closing ")"?

It might be easier if you used lists for this:

val = ['linux', ['kernel', fn]]
val.append(['ramdisk', fn])
val.append(['args', img.args])
os.write(fd, sxp.to_string(val))

This will take care of the brackets, and any string quoting needed.

BTW, I used 'val' to avoid colliding with the 'sxp' module.

+
+    sys.stdout.flush()
+    os.write(fd, sxp)
+

------------------------------------------------------------------------

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel