# 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 +# +# 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 +# +# 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 +# +# 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(" + * + * 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 + +#include +#include +#include + +#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 +# +# 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("= 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=] " %(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,) + + sys.stdout.flush() + os.write(fd, sxp) +