I've hacked a python interface onto vblade by embedding python into vblade.

This means that instead of pointing vblade at a block device or file,
you can point it at a python program.

Eg

  sudo ./vblade -p 1 2 lo file_driver.py params

This is very useful for experimenting with block devices, and for
implementing more "interesting" storage backends.

The python interface looks like this (this driver does the same thing as
vblade)

class Driver(object):
    SECTOR_SIZE = 512
    def __init__(self, *args, **kwargs):
        """
        Initialise
        """
        self.size = 16*1024*1024
        self.path = "/tmp/aoe_test_file"
        self.fd = open(self.path, "wb+")
    def getsec(self, position, size):
        """
        Reads size bytes at position, returning a string with them in
        """
        self.fd.seek(position, os.SEEK_SET)
        return self.fd.read(size)
    def putsec(self, position, bytes):
        """
        Writes the bytes passed in at the position

        Returns an integer bytes written, -1 for failure
        """
        self.fd.seek(position, os.SEEK_SET)
        self.fd.write(bytes)
        return len(bytes)
    def getsize(self):
        """
        Returns the size of the image in bytes
        """
        return self.size

I've attached a preliminary patch against the release v20 tarball.

I'd be interested to know
  * is this the kind of thing you'd like to merge?
  * should the python interface be a compile time option or not?
  * any comments on implementation

Things not done yet
  * BSD interface
  * Restart script on errors
  * Use the passed in parameters

Cheers

Nick
-- 
Nick Craig-Wood <n...@craig-wood.com> -- http://www.craig-wood.com/nick
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..304077f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+*.o
+*~
+/vblade
diff --git a/aoe.c b/aoe.c
index 0ab0b99..76353b4 100644
--- a/aoe.c
+++ b/aoe.c
@@ -11,6 +11,7 @@
 #include <netinet/in.h>
 #include "dat.h"
 #include "fns.h"
+#include "pi.h"
 
 enum {
 	Nmasks= 32,
@@ -379,7 +380,7 @@ aoe(void)
 void
 usage(void)
 {
-	fprintf(stderr, "usage: %s [-b bufcnt] [-d ] [-s] [-r] [ -m mac[,mac...] ] shelf slot netif filename\n", 
+	fprintf(stderr, "usage: %s [-b bufcnt] [-d ] [-s] [-r] [ -m mac[,mac...] ] [-p] shelf slot netif filename [options]\n", 
 		progname);
 	exit(1);
 }
@@ -466,7 +467,7 @@ main(int argc, char **argv)
 	bufcnt = Bufcount;
 	setbuf(stdin, NULL);
 	progname = *argv;
-	while ((ch = getopt(argc, argv, "b:dsrm:")) != -1) {
+	while ((ch = getopt(argc, argv, "b:dsrm:p")) != -1) {
 		switch (ch) {
 		case 'b':
 			bufcnt = atoi(optarg);
@@ -485,6 +486,9 @@ main(int argc, char **argv)
 		case 'm':
 			setmask(optarg);
 			break;
+		case 'p':
+			using_python_interface = 1;
+			break;
 		case '?':
 		default:
 			usage();
@@ -492,13 +496,17 @@ main(int argc, char **argv)
 	}
 	argc -= optind;
 	argv += optind;
-	if (argc != 4 || bufcnt <= 0)
+	if (argc < 4 || bufcnt <= 0)
 		usage();
 	omode |= readonly ? O_RDONLY : O_RDWR;
-	bfd = open(argv[3], omode);
-	if (bfd == -1) {
-		perror("open");
-		exit(1);
+	if (using_python_interface) {
+		pi_init(argc-3, &argv[3]); /* call with script name and any extra arguments */
+	} else {
+		bfd = open(argv[3], omode);
+		if (bfd == -1) {
+			perror("open");
+			exit(1);
+		}
 	}
 	shelf = atoi(argv[0]);
 	slot = atoi(argv[1]);
diff --git a/file_driver.py b/file_driver.py
new file mode 100644
index 0000000..d69389a
--- /dev/null
+++ b/file_driver.py
@@ -0,0 +1,43 @@
+import os
+
+class Driver(object):
+    """
+    Driver for AOE
+    """
+    SECTOR_SIZE = 512
+    def __init__(self, *args, **kwargs):
+        """
+        Initialise
+        """
+        print "args = %r, kwargs = %r" % (args, kwargs)
+        self.size = 16*1024*1024
+        self.path = "/tmp/aoe_test_file"
+        if not os.path.exists(self.path):
+            self.fd = open(self.path, "wb+")
+            self.fd.truncate(self.size)
+        else:
+            self.fd = open(self.path, "rb+")
+            self.size = os.path.getsize(self.path)
+    def getsec(self, position, size):
+        """
+        Reads size bytes at position, returning a string with them in
+        """
+        print "< getsec(%d,%d)" % (position, size)
+        self.fd.seek(position, os.SEEK_SET)
+        return self.fd.read(size)
+    def putsec(self, position, bytes):
+        """
+        Writes the bytes passed in at the position
+
+        Returns an integer bytes written, -1 for failure
+        """
+        print "> putsec(%d,%d)" % (position, len(bytes))
+        self.fd.seek(position, os.SEEK_SET)
+        self.fd.write(bytes)
+        return len(bytes)
+    def getsize(self):
+        """
+        Returns the size of the image in bytes
+        """
+        print "= getsize = %d" % self.size
+        return self.size
diff --git a/linux.c b/linux.c
index 11aa2e7..f59b9b6 100644
--- a/linux.c
+++ b/linux.c
@@ -27,6 +27,7 @@
 
 #include "dat.h"
 #include "fns.h"
+#include "pi.h"
 
 int	getindx(int, char *);
 int	getea(int, char *, uchar *);
@@ -119,12 +120,16 @@ getmtu(int s, char *name)
 int
 getsec(int fd, uchar *place, vlong lba, int nsec)
 {
+	if (using_python_interface)
+		return pi_getsec(place, lba, nsec);
 	return pread(fd, place, nsec * 512, lba * 512);
 }
 
 int
 putsec(int fd, uchar *place, vlong lba, int nsec)
 {
+	if (using_python_interface)
+		return pi_putsec(place, lba, nsec);
 	return pwrite(fd, place, nsec * 512, lba * 512);
 }
 
@@ -147,6 +152,9 @@ getsize(int fd)
 	struct stat s;
 	int n;
 
+	if (using_python_interface)
+		return pi_getsize();
+
 	n = ioctl(fd, BLKGETSIZE64, &size);
 	if (n == -1) {	// must not be a block special
 		n = fstat(fd, &s);
diff --git a/makefile b/makefile
index 9613087..0788855 100644
--- a/makefile
+++ b/makefile
@@ -8,12 +8,13 @@ sbindir = ${prefix}/sbin
 sharedir = ${prefix}/share
 mandir = ${sharedir}/man
 
-O=aoe.o bpf.o ${PLATFORM}.o ata.o
-CFLAGS += -Wall -g -O2
+LIBS=$(shell python-config --libs)
+O=aoe.o bpf.o ${PLATFORM}.o ata.o pi.o
+CFLAGS += -Wall -g -O2 $(shell python-config --includes)
 CC = gcc
 
 vblade: $O
-	${CC} -o vblade $O
+	${CC} -o vblade $O $(LIBS)
 
 aoe.o : aoe.c config.h dat.h fns.h makefile
 	${CC} ${CFLAGS} -c $<
diff --git a/pi.c b/pi.c
new file mode 100644
index 0000000..1e1370a
--- /dev/null
+++ b/pi.c
@@ -0,0 +1,201 @@
+/* Python interface */
+
+#include <Python.h>
+#include <stdio.h>
+#include <netinet/in.h>		/* for ushort */
+#include "dat.h"
+#include "pi.h"
+
+
+int using_python_interface = 0;
+static PyObject *pi_driver_class = NULL;
+static PyObject *pi_driver = NULL;
+
+static PyObject *pi_load_driver(const char *script)
+{
+	PyObject *globals = NULL;
+	PyObject *result = NULL;
+	PyObject *driver_class = NULL;
+	FILE *fp = NULL;
+
+	/* load in the code */
+	globals = Py_BuildValue(	/* new ref */
+	    (char *)"{sO}", 
+	    "__builtins__",	PyEval_GetBuiltins()
+	    );
+	if (globals == 0)
+	{
+	    fprintf(stderr, "Failed to allocate globals for '%s'\n", script);
+	    exit(1);
+	}
+
+	fp = fopen(script, "r");
+	if (!fp)
+	{
+	    fprintf(stderr, "Couldn't open '%s'\n", script);
+	    exit(1);
+	}
+
+	result = PyRun_FileEx(fp, script, Py_file_input, globals, globals, 0); /* new ref */
+	if (!result)
+	{
+	    PyErr_Print();
+	    fprintf(stderr, "Failed to run '%s'\n", script);
+	    exit(1);
+	}
+	
+	/* load the Driver class from the module */
+	driver_class = PyDict_GetItemString(globals, "Driver"); /* borrowed */
+	if (!driver_class)
+	{
+	    PyErr_Print();
+	    fprintf(stderr, "Failed to load 'Driver' class from '%s'\n", script);
+	    exit(1);;
+	}
+	Py_INCREF(driver_class); /* keep our own reference please */
+
+	if (fp)
+	    fclose(fp);
+	Py_XDECREF(result);
+	Py_XDECREF(globals);
+	return driver_class;
+}
+
+static PyObject *pi_instantiate_driver(PyObject *driver_class, int argc, char *argv[])
+{
+    PyObject *args = NULL;
+    PyObject *kwargs = NULL;
+    PyObject *driver = NULL;
+
+    /* Cheap and nasty code alert ;-) */
+    switch (argc) {
+    case 0:
+	    args = Py_BuildValue((char *)"()"); /* new ref */
+	    break;
+    case 1:
+	    args = Py_BuildValue((char *)"(s)", argv[0]); /* new ref */
+	    break;
+    case 2:
+	    args = Py_BuildValue((char *)"(ss)", argv[0], argv[1]); /* new ref */
+	    break;
+    case 3:
+	    args = Py_BuildValue((char *)"(sss)", argv[0], argv[1], argv[2]); /* new ref */
+	    break;
+    case 4:
+	    args = Py_BuildValue((char *)"(ssss)", argv[0], argv[1], argv[2], argv[3]); /* new ref */
+	    break;
+    default:
+	    fprintf(stderr, "Too many arguments to python driver\n");
+	    exit(1);
+	    break;
+    }
+    kwargs = Py_BuildValue((char *)"{}"); /* new ref */
+    driver = PyObject_Call(driver_class, args, kwargs); /* new ref */
+    if (!driver)
+    {
+	PyErr_Print();
+	fprintf(stderr, "Failed to create an instance of python driver\n");
+	exit(1);
+    }
+
+    Py_XDECREF(args);
+    Py_XDECREF(kwargs);
+    return driver;
+}
+
+/*
+Initialise the python driver
+Called with the script name and any remaining arguments
+ */
+
+void
+pi_init(int argc, char *argv[]) {
+	Py_Initialize();
+	pi_driver_class = pi_load_driver(argv[0]);
+	pi_driver = pi_instantiate_driver(pi_driver_class, argc-1, &argv[1]);
+}
+
+int
+pi_getsec(uchar *place, vlong lba, int nsec)
+{
+	int in_size = 512 * nsec;
+	PyObject *py_result = PyObject_CallMethod(pi_driver, (char *)"getsec", (char *)"(li)", lba * 512, in_size); /* new ref */
+	int result;
+	if (py_result)
+	{
+		char *buffer;
+		Py_ssize_t length;
+		if (PyString_AsStringAndSize(py_result, &buffer, &length) != -1) {
+			if (length > in_size) {
+				length = in_size;
+			}
+			memcpy(place, buffer, length);
+			result = length;
+		} else {
+			PyErr_Print();
+			result = 0;
+		}
+		Py_DECREF(py_result);
+	}
+	else
+	{
+		PyErr_Print();
+		result = 0;
+	}
+	return result;
+}
+
+int
+pi_putsec(uchar *place, vlong lba, int nsec)
+{
+	int in_size = 512 * nsec;
+	PyObject *in_buffer = PyString_FromStringAndSize((const char *)place, in_size); /* new ref */
+	if (!in_buffer) {
+		PyErr_Print();
+		return 0;
+	}
+	PyObject *py_result = PyObject_CallMethod(pi_driver, (char *)"putsec", (char *)"(lO)", lba * 512, in_buffer); /* new ref */
+	Py_DECREF(in_buffer);
+	int result;
+	if (py_result)
+	{
+		result = PyInt_AsLong(py_result);
+		Py_DECREF(py_result);
+		if (result == -1 && PyErr_Occurred())
+		{
+			PyErr_Print();
+			result = -1;
+		}
+	}
+	else
+	{
+		PyErr_Print();
+		result = -1;
+	}
+	return result;
+}
+
+vlong
+pi_getsize(void)
+{
+	PyObject *py_result = PyObject_CallMethod(pi_driver, (char *)"getsize", NULL); /* new ref */
+	vlong result;
+	if (py_result)
+	{
+		result = PyInt_AsLong(py_result);
+		Py_DECREF(py_result);
+		if (result == -1 && PyErr_Occurred())
+		{
+			PyErr_Print();
+			fprintf(stderr, "Failed to read size from python driver\n");
+			exit(1);
+		}
+	}
+	else
+	{
+		PyErr_Print();
+		fprintf(stderr, "Failed to read size from python driver\n");
+		exit(1);
+	}
+	return result;
+}
diff --git a/pi.h b/pi.h
new file mode 100644
index 0000000..f00549d
--- /dev/null
+++ b/pi.h
@@ -0,0 +1,15 @@
+/* Python interface */
+
+extern int using_python_interface;
+
+void
+pi_init(int argc, char *argv[]);
+
+int
+pi_getsec(uchar *place, vlong lba, int nsec);
+
+int
+pi_putsec(uchar *place, vlong lba, int nsec);
+
+vlong
+pi_getsize(void);
diff --git a/vblade.8 b/vblade.8
index 2cd2b2c..ef5b2c5 100644
--- a/vblade.8
+++ b/vblade.8
@@ -55,6 +55,10 @@ The -r flag restricts the export of the device to be read-only.
 The -m flag takes an argument, a comma separated list of MAC addresses
 permitted access to the vblade.  A MAC address can be specified in upper
 or lower case, with or without colons.
+.TP
+\fB-p\fP
+The -p flag indicates that the device is actually a python script to
+be loaded and called to read and write blocks
 .SH EXAMPLE
 In this example, the root user on a host named
 .I nai
------------------------------------------------------------------------------
Lotusphere 2011
Register now for Lotusphere 2011 and learn how
to connect the dots, take your collaborative environment
to the next level, and enter the era of Social Business.
http://p.sf.net/sfu/lotusphere-d2d
_______________________________________________
Aoetools-discuss mailing list
Aoetools-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/aoetools-discuss

Reply via email to