diff -Nurp xen-3.1.0-src.orig/tools/libfsimage/common/fsimage.c xen-3.1.0-src/tools/libfsimage/common/fsimage.c
--- xen-3.1.0-src.orig/tools/libfsimage/common/fsimage.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src/tools/libfsimage/common/fsimage.c	2009-08-25 12:23:21.000000000 -0400
@@ -21,6 +21,7 @@
  * Use is subject to license terms.
  */
 
+#define _GNU_SOURCE
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <strings.h>
@@ -42,7 +43,7 @@ fsi_t *fsi_open_fsimage(const char *path
 	int fd;
 	int err;
 
-	if ((fd = open(path, O_RDONLY)) == -1)
+	if ((fd = open(path, O_RDONLY | O_DIRECT)) == -1)
 		goto fail;
 
 	if ((fsi = malloc(sizeof(*fsi))) == NULL)
diff -Nurp xen-3.1.0-src.orig/tools/libfsimage/common/fsimage_grub.c xen-3.1.0-src/tools/libfsimage/common/fsimage_grub.c
--- xen-3.1.0-src.orig/tools/libfsimage/common/fsimage_grub.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src/tools/libfsimage/common/fsimage_grub.c	2009-08-25 12:21:39.000000000 -0400
@@ -22,11 +22,13 @@
  */
 
 #ifndef __sun__
-#define	_XOPEN_SOURCE 500
+#define	_XOPEN_SOURCE 600
 #endif
 #include <stdlib.h>
 #include <strings.h>
 #include <errno.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "fsimage_grub.h"
 #include "fsimage_priv.h"
@@ -206,20 +209,52 @@ fsig_devread(fsi_file_t *ffi, unsigned i
 {
 	uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)sector * 512) + offset;
 	ssize_t bytes_read = 0;
+	long pagesize;
+	void *aligned_buffer;
+	int retval = 1;
+	int toread;
+	int memret;
+
+	pagesize = sysconf(_SC_PAGE_SIZE);
+	if (pagesize < 0)
+		return 0;
+
+	toread = (bufsize + pagesize - 1) & ~(pagesize-1);
+	memret = posix_memalign(&aligned_buffer, pagesize, toread);
+	if (memret != 0) {
+		errno = memret;
+		return 0;
+	}
 
 	while (bufsize) {
-		ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read,
-		    bufsize, (off_t)off);
-		if (ret == -1)
-			return (0);
-		if (ret == 0)
-			return (0);
+		ssize_t ret;
+		ssize_t toread;
+
+		toread = (bufsize + pagesize - 1) & ~(pagesize-1);
+		ret = pread(ffi->ff_fsi->f_fd, aligned_buffer,
+		    toread, (off_t)off);
+
+		if (ret == -1) {
+			retval = 0;
+			goto cleanup;
+		}
+		if (ret == 0) {
+			retval = 0;
+			goto cleanup;
+		}
+
+		if (ret > bufsize)
+			ret = bufsize;
+
+		memcpy(buf + bytes_read, aligned_buffer, ret);
 
 		bytes_read += ret;
 		bufsize -= ret;
 	}
 
-	return (1);
+ cleanup:
+	free(aligned_buffer);
+	return retval;
 }
 
 int
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/setup.py xen-3.1.0-src/tools/pygrub/setup.py
--- xen-3.1.0-src.orig/tools/pygrub/setup.py	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src/tools/pygrub/setup.py	2009-08-25 10:26:07.000000000 -0400
@@ -14,6 +14,10 @@ fsimage = Extension("fsimage",
     libraries = ["fsimage"],
     sources = ["src/fsimage/fsimage.c"])
 
+pygrubutils = Extension("pygrubutils",
+    extra_compile_args = extra_compile_args,
+    sources = ["src/pygrubutils/pygrubutils.c"])
+
 pkgs = [ 'grub' ]
 
 setup(name='pygrub',
@@ -22,8 +26,8 @@ setup(name='pygrub',
       author='Jeremy Katz',
       author_email='katzj@redhat.com',
       license='GPL',
-      package_dir={'grub': 'src', 'fsimage': 'src'},
+      package_dir={'grub': 'src', 'fsimage': 'src', 'pygrubutils': 'src'},
       scripts = ["src/pygrub"],
       packages=pkgs,
-      ext_modules = [ fsimage ]
+      ext_modules = [ fsimage, pygrubutils ]
       )
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/src/fsimage/fsimage.c xen-3.1.0-src/tools/pygrub/src/fsimage/fsimage.c
--- xen-3.1.0-src.orig/tools/pygrub/src/fsimage/fsimage.c	2007-05-18 10:45:21.000000000 -0400
+++ xen-3.1.0-src/tools/pygrub/src/fsimage/fsimage.c	2009-08-25 12:24:47.000000000 -0400
@@ -25,6 +25,7 @@
 
 #include <fsimage.h>
 #include <stdlib.h>
+#include <errno.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
@@ -55,10 +56,13 @@ fsimage_file_read(fsimage_file_t *file, 
 {
 	static char *kwlist[] = { "size", "offset", NULL };
 	int bufsize;
+	int ret;
 	int size = 0;
 	uint64_t offset = 0;
 	ssize_t bytesread = 0;
-	PyObject * buffer;
+	void *buffer, *newbuf;
+	long pagesize;
+	int toread;
 
 	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|iL", kwlist, 
 	    &size, &offset))
@@ -66,18 +70,30 @@ fsimage_file_read(fsimage_file_t *file, 
 
 	bufsize = size ? size : 4096;
 
-	if ((buffer = PyString_FromStringAndSize(NULL, bufsize)) == NULL)
+	pagesize = sysconf(_SC_PAGE_SIZE);
+	if (pagesize < 0) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return (NULL);
+	}
+
+	toread = (bufsize + pagesize - 1) & ~(pagesize-1);
+	ret = posix_memalign(&buffer, pagesize, toread);
+	if (ret != 0) {
+		errno = ret;
+		PyErr_SetFromErrno(PyExc_IOError);
 		return (NULL);
- 
+	}
+
 	while (1) {
 		int err;
-		void *buf = PyString_AS_STRING(buffer) + bytesread;
+		void *buf = buffer + bytesread;
 
-		err = fsi_pread_file(file->file, buf, bufsize,
+		toread = (bufsize + pagesize - 1) & ~(pagesize-1);
+		err = fsi_pread_file(file->file, buf, toread,
 		    bytesread + offset);
-			
+
 		if (err == -1) {
-			Py_DECREF(buffer);
+			free(buffer);
 			PyErr_SetFromErrno(PyExc_IOError);
 			return (NULL);
 		} else if (err == 0) {
@@ -91,13 +107,21 @@ fsimage_file_read(fsimage_file_t *file, 
 			if (bufsize == 0)
 				break;
 		} else {
-			if (_PyString_Resize(&buffer, bytesread + bufsize) < 0)
+			toread = ((bytesread + bufsize) + pagesize - 1) & ~(pagesize-1);
+			ret = posix_memalign(&newbuf, pagesize, toread);
+			if (ret != 0) {
+				free(buffer);
+				errno = ret;
+				PyErr_SetFromErrno(PyExc_IOError);
 				return (NULL);
+			}
+			memcpy(newbuf, buffer, bytesread);
+			free(buffer);
+			buffer = newbuf;
 		}
 	}
 
-	_PyString_Resize(&buffer, bytesread);
-	return (buffer);
+	return PyString_FromStringAndSize(buffer, bytesread);
 }
 
 PyDoc_STRVAR(fsimage_file_read__doc__,
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/src/GrubConf.py xen-3.1.0-src/tools/pygrub/src/GrubConf.py
--- xen-3.1.0-src.orig/tools/pygrub/src/GrubConf.py	2009-08-25 09:56:52.000000000 -0400
+++ xen-3.1.0-src/tools/pygrub/src/GrubConf.py	2009-08-25 10:26:07.000000000 -0400
@@ -14,6 +14,7 @@
 
 import os, sys
 import logging
+from pygrubutils import *
 
 def grub_split(s, maxsplit = -1):
     eq = s.find('=')
@@ -166,9 +167,7 @@ class GrubConfigFile(object):
             if self.filename is None:
                 raise ValueError, "No config file defined to parse!"
 
-            f = open(self.filename, 'r')
-            lines = f.readlines()
-            f.close()
+            lines = readlines_direct(self.filename)
         else:
             lines = buf.split("\n")
 
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/src/LiloConf.py xen-3.1.0-src/tools/pygrub/src/LiloConf.py
--- xen-3.1.0-src.orig/tools/pygrub/src/LiloConf.py	2009-08-25 09:56:53.000000000 -0400
+++ xen-3.1.0-src/tools/pygrub/src/LiloConf.py	2009-08-25 10:26:07.000000000 -0400
@@ -5,6 +5,7 @@
 import sys, re, os
 import logging
 import GrubConf
+from pygrubutils import *
 
 class LiloImage(object):
     def __init__(self, lines, path):
@@ -99,9 +100,7 @@ class LiloConfigFile(object):
             if self.filename is None:
                 raise ValueError, "No config file defined to parse!"
 
-            f = open(self.filename, 'r')
-            lines = f.readlines()
-            f.close()
+            lines = readlines_direct(self.filename)
         else:
             lines = buf.split("\n")
 
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/src/pygrub xen-3.1.0-src/tools/pygrub/src/pygrub
--- xen-3.1.0-src.orig/tools/pygrub/src/pygrub	2009-08-25 09:56:55.000000000 -0400
+++ xen-3.1.0-src/tools/pygrub/src/pygrub	2009-08-25 10:26:07.000000000 -0400
@@ -26,6 +26,7 @@ sys.path = [ '/usr/lib/python' ] + sys.p
 import fsimage
 import grub.GrubConf
 import grub.LiloConf
+from pygrubutils import *
 
 PYGRUB_VER = 0.6
 
@@ -40,62 +41,7 @@ def enable_cursor(ison):
     except _curses.error:
         pass
 
-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]) == (0xaa55,):
-        return True
-    return False
-
-def get_active_partition(file):
-    """Find the offset for the start of the first active partition "
-    "in the disk image file."""
-
-    fd = os.open(file, os.O_RDONLY)
-    buf = os.read(fd, 512)
-    for poff in (446, 462, 478, 494): # partition offsets
-        # active partition has 0x80 as the first byte
-        if struct.unpack("<c", buf[poff:poff+1]) == ('\x80',):
-            return buf[poff:poff+16]
-
-    # if there's not a partition marked as active, fall back to
-    # the first partition
-    return buf[446:446+16]
-
 SECTOR_SIZE=512
-DK_LABEL_LOC=1
-DKL_MAGIC=0xdabe
-V_ROOT=0x2
-
-def get_solaris_slice(file, offset):
-    """Find the root slice in a Solaris VTOC."""
-
-    fd = os.open(file, os.O_RDONLY)
-    os.lseek(fd, offset + (DK_LABEL_LOC * SECTOR_SIZE), 0)
-    buf = os.read(fd, 512)
-    if struct.unpack("<H", buf[508:510])[0] != DKL_MAGIC:
-        raise RuntimeError, "Invalid disklabel magic"
-
-    nslices = struct.unpack("<H", buf[30:32])[0]
-
-    for i in range(nslices):
-        sliceoff = 72 + 12 * i
-        slicetag = struct.unpack("<H", buf[sliceoff:sliceoff+2])[0]
-        slicesect = struct.unpack("<L", buf[sliceoff+4:sliceoff+8])[0]
-        if slicetag == V_ROOT:
-            return slicesect * SECTOR_SIZE
-
-    raise RuntimeError, "No root slice found"      
-
-def get_fs_offset_gpt(file):
-    fd = os.open(file, os.O_RDONLY)
-    # assume the first partition is an EFI system partition.
-    os.lseek(fd, SECTOR_SIZE * 2, 0)
-    buf = os.read(fd, 512)
-    return struct.unpack("<Q", buf[32:40])[0] * SECTOR_SIZE
 
 FDISK_PART_SOLARIS=0xbf
 FDISK_PART_SOLARIS_OLD=0x82
diff -Nurp xen-3.1.0-src.orig/tools/pygrub/src/pygrubutils/pygrubutils.c xen-3.1.0-src/tools/pygrub/src/pygrubutils/pygrubutils.c
--- xen-3.1.0-src.orig/tools/pygrub/src/pygrubutils/pygrubutils.c	1969-12-31 19:00:00.000000000 -0500
+++ xen-3.1.0-src/tools/pygrub/src/pygrubutils/pygrubutils.c	2009-08-25 10:26:07.000000000 -0400
@@ -0,0 +1,323 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <Python.h>
+
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+/* read 'bytes' number of bytes out of filename 'filename' starting at
+ * offset 'offset', using O_DIRECT.  Returns the pagesize aligned buffer
+ * containing the data on success, NULL on error.  Caller must free the buffer
+ */
+static void *direct_read_file(char *filename, uint64_t offset, ssize_t bytes)
+{
+	int fd = -1;
+	void *buffer = NULL;
+	long pagesize;
+	ssize_t ret, bytesread;
+	int toread;
+
+	pagesize = sysconf(_SC_PAGE_SIZE);
+	if (pagesize < 0)
+		goto error;
+
+	toread = (bytes + pagesize - 1) & ~(pagesize-1);
+	ret = posix_memalign(&buffer, pagesize, toread);
+	if (ret != 0) {
+		errno = ret;
+		goto error;
+	}
+
+	fd = open(filename, O_RDONLY | O_DIRECT);
+	if (fd < 0)
+		goto error;
+
+	if (lseek(fd, offset, SEEK_SET) < 0)
+		goto error;
+
+	bytesread = 0;
+	while (1) {
+		toread = ((bytes - bytesread) + pagesize - 1) & ~(pagesize-1);
+		ret = read(fd, buffer + bytesread, toread);
+
+		if (ret < 0)
+			goto error;
+		else if (ret == 0)
+			break;
+
+		bytesread += ret;
+	}
+
+	close(fd);
+
+	if (bytesread < bytes) {
+		/* FIXME: set errno here */
+		goto error;
+	}
+
+	return buffer;
+
+ error:
+	if (fd != -1)
+		close(fd);
+	free(buffer);
+	return NULL;
+}
+
+static PyObject *
+pygrubutils_readlines_direct(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "name", NULL };
+	char *name;
+	unsigned char *buffer = NULL;
+	struct stat sb;
+	PyObject *list = NULL;
+	int i;
+	unsigned char *curr;
+	int len;
+	char *thisline;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+		return (NULL);
+
+	/* FIXME: error checking */
+	stat(name, &sb);
+
+	buffer = direct_read_file(name, 0, sb.st_size);
+	if (buffer == NULL) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		goto cleanup;
+	}
+
+	/* we should have the whole file, so build a list with all lines */
+	curr = buffer;
+	list = PyList_New(0);
+	for (i = 0; i < sb.st_size ; i++) {
+		if (buffer[i] != '\n')
+			continue;
+		/* if we made it here, then we have a full line behind us */
+		len = (buffer + i) - curr;
+		thisline = malloc(len + 1);
+		memcpy(thisline, curr, len);
+		thisline[len] = '\0';
+		PyList_Append(list, PyString_FromString(thisline));
+		curr = buffer + i + 1;
+	}
+
+ cleanup:
+	free(buffer);
+
+	return list;
+}
+
+#define SECTOR_SIZE 512
+static PyObject *
+pygrubutils_get_fs_offset_gpt(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "name", NULL };
+	char *name;
+	unsigned char *buffer = NULL;
+	uint64_t data;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+		return (NULL);
+
+	buffer = direct_read_file(name, SECTOR_SIZE * 2, 512);
+	if (buffer == NULL) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		return NULL;
+	}
+
+	data = (((uint64_t)buffer[32]) << 56) | (((uint64_t)buffer[33]) << 48)
+	  | (((uint64_t)buffer[34]) << 40) | (((uint64_t)buffer[35]) << 32)
+	  | (((uint64_t)buffer[36]) << 24) | (((uint64_t)buffer[37]) << 16)
+	  | (((uint64_t)buffer[38]) << 8) | ((uint64_t)buffer[39]);
+
+	free(buffer);
+
+	return PyLong_FromUnsignedLong(data);
+}
+
+#define DK_LABEL_LOC 1
+#define V_ROOT 0x2
+static PyObject *
+pygrubutils_get_solaris_slice(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "name", "offset", NULL };
+	char *name;
+	unsigned char *buffer = NULL;
+	uint64_t offset;
+	unsigned short nslices;
+	int i;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sL", kwlist, &name, &offset))
+		return (NULL);
+
+	buffer = direct_read_file(name, offset + (DK_LABEL_LOC * SECTOR_SIZE), 512);
+	if (buffer == NULL) {
+		PyErr_SetFromErrno(PyExc_IOError);
+		goto error;
+	}
+
+	/* DKL magic */
+	if (buffer[508] != 0xda || buffer[509] != 0xbe) {
+		PyErr_Format(PyExc_RuntimeError, "Invalid disklabel magic");
+		goto error;
+	}
+
+	/* FIXME: is this correct endianness? */
+	nslices = buffer[30] << 8 | buffer[31];
+
+	for (i = 0; i < nslices; i++) {
+		int sliceoff;
+		unsigned short slicetag;
+		unsigned long slicesect;
+
+		sliceoff = 72 + 12 * i;
+		slicetag = buffer[sliceoff] << 8 | buffer[sliceoff + 1];
+		slicesect = buffer[sliceoff + 4] << 24 | buffer[sliceoff + 5] << 16 |
+		  buffer[sliceoff + 6] << 8 | buffer[sliceoff + 7];
+
+		if (slicetag == V_ROOT) {
+			free (buffer);
+			return PyInt_FromLong(slicesect * SECTOR_SIZE);
+		}
+	}
+
+	PyErr_Format(PyExc_RuntimeError, "No root slice found");
+	free(buffer);
+	return NULL;
+
+ error:
+	free(buffer);
+	return NULL;
+}
+
+static PyObject *
+pygrubutils_get_active_partition(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "name", NULL };
+	char *name;
+	char *partbuf;
+	unsigned char *buffer = NULL;
+	int offset;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+		return (NULL);
+
+	buffer = direct_read_file(name, 0, 512);
+	if (buffer == NULL)
+		goto error;
+
+	if (buffer[0x1be] == 0x80)
+		offset = 0x1be;
+	else if (buffer[0x1ce] == 0x80)
+		offset = 0x1ce;
+	else if (buffer[0x1de] == 0x80)
+		offset = 0x1de;
+	else if (buffer[0x1ee] == 0x80)
+		offset = 0x1ee;
+	else
+		offset = 0x1be;
+
+	partbuf = malloc(16);
+	if (partbuf == NULL) {
+		free(buffer);
+		PyErr_NoMemory();
+		return NULL;
+	}
+	memcpy(partbuf, buffer + offset, 16);
+
+	free(buffer);
+
+	return PyString_FromStringAndSize(partbuf, 16);
+
+ error:
+	free(buffer);
+	PyErr_SetFromErrno(PyExc_IOError);
+	return NULL;
+}
+
+static PyObject *
+pygrubutils_is_disk_image(PyObject *o, PyObject *args, PyObject *kwargs)
+{
+	static char *kwlist[] = { "name", NULL };
+	char *name;
+	unsigned char *buffer = NULL;
+
+	if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s", kwlist, &name))
+		return (Py_False);
+
+	buffer = direct_read_file(name, 0, 512);
+	if (buffer == NULL)
+		goto error;
+
+	if ((buffer[0x1fe] != 0x55) || (buffer[0x1ff] != 0xaa)) {
+		free(buffer);
+		return (Py_False);
+	}
+
+	free(buffer);
+	return (Py_True);
+
+ error:
+	free(buffer);
+	PyErr_SetFromErrno(PyExc_IOError);
+	return NULL;
+}
+
+PyDoc_STRVAR(pygrubutils_is_disk_image__doc__,
+	     "is_disk_image(name) - Figure out if the given file is a valid disk image\n");
+PyDoc_STRVAR(pygrubutils_get_active_partition__doc__,
+	     "get_active_partition(name) - Get the active partition out of a disk image\n");
+PyDoc_STRVAR(pygrubutils_get_solaris_slice__doc__,
+	     "get_solaris_slice(name, offset) - Get the solaris slice out of a disk image\n");
+PyDoc_STRVAR(pygrubutils_get_fs_offset_gpt__doc__,
+	     "get_fs_offset_gpt(name) - Get the FS GPT offset out of a disk image\n");
+PyDoc_STRVAR(pygrubutils_readlines_direct__doc__,
+	     "readlines_direct(name) - Read all lines from a file, using O_DIRECT\n");
+
+static struct PyMethodDef pygrubutils_module_methods[] = {
+	{ "is_disk_image", (PyCFunction)pygrubutils_is_disk_image,
+	    METH_VARARGS|METH_KEYWORDS, pygrubutils_is_disk_image__doc__ },
+	{ "get_active_partition", (PyCFunction)pygrubutils_get_active_partition,
+	    METH_VARARGS|METH_KEYWORDS, pygrubutils_get_active_partition__doc__ },
+	{ "get_solaris_slice", (PyCFunction)pygrubutils_get_solaris_slice,
+	    METH_VARARGS|METH_KEYWORDS, pygrubutils_get_solaris_slice__doc__ },
+	{ "get_fs_offset_gpt", (PyCFunction)pygrubutils_get_fs_offset_gpt,
+	    METH_VARARGS|METH_KEYWORDS, pygrubutils_get_fs_offset_gpt__doc__ },
+	{ "readlines_direct", (PyCFunction)pygrubutils_readlines_direct,
+	    METH_VARARGS|METH_KEYWORDS, pygrubutils_readlines_direct__doc__ },
+	{ NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC
+initpygrubutils(void)
+{
+	Py_InitModule("pygrubutils", pygrubutils_module_methods);
+}
