Beginnings of vserver module to support manipulation of vservers without
Steve Muir [Fri, 20 May 2005 21:45:19 +0000 (21:45 +0000)]
jumping through shell hoops

python/Makefile [new file with mode: 0644]
python/vserver.py [new file with mode: 0644]
python/vserverimpl.c [new file with mode: 0644]

diff --git a/python/Makefile b/python/Makefile
new file mode 100644 (file)
index 0000000..3b8879d
--- /dev/null
@@ -0,0 +1,16 @@
+INCLUDES := -I.. -I../lib -I/usr/include/python2.3
+CPPFLAGS = $(DEFS) $(INCLUDES)
+CFLAGS = $(CPPFLAGS) -g -Wall
+COMPILE = $(CC) $(CFLAGS)
+LIBS = -L../lib -lvserver
+LINK = $(CC) $(LDFLAGS)
+
+PY_MODS := passfdimpl.so
+
+all: $(PY_MODS)
+
+$(PY_MODS): %.so: %.o
+       $(LINK) -shared -o $@ $^ $(LIBS)
+
+%.o: %.c
+       $(COMPILE) -c $<
diff --git a/python/vserver.py b/python/vserver.py
new file mode 100644 (file)
index 0000000..feeb026
--- /dev/null
@@ -0,0 +1,126 @@
+# Copyright 2005 Princeton University
+
+import errno
+import fcntl
+import os
+import re
+
+import linuxcaps
+import passfdimpl
+
+from vserver_vars import *
+
+CAP_SAFE = (linuxcaps.CAP_CHOWN |
+            linuxcaps.CAP_DAC_OVERRIDE |
+            linuxcaps.CAP_DAC_READ_SEARCH |
+            linuxcaps.CAP_FOWNER |
+            linuxcaps.CAP_FSETID |
+            linuxcaps.CAP_KILL |
+            linuxcaps.CAP_SETGID |
+            linuxcaps.CAP_SETUID |
+            linuxcaps.CAP_SETPCAP |
+            linuxcaps.CAP_SYS_TTY_CONFIG |
+            linuxcaps.CAP_LEASE |
+            linuxcaps.CAP_SYS_CHROOT |
+            linuxcaps.CAP_SYS_PTRACE)
+
+#
+# XXX - these are the flags taken from chcontext.c, but they don't match
+# up with those apparently used by the kernel
+#
+FLAGS_LOCK = 1
+FLAGS_SCHED = 2
+FLAGS_NPROC = 4
+FLAGS_PRIVATE = 8
+FLAGS_FAKEINIT = 16
+FLAGS_HIDEINFO = 32
+FLAGS_ULIMIT = 64
+
+
+              
+class VServer:
+
+    def __init__(self, name):
+
+        self.name = name
+        self.config = self.__read_config_file("/etc/vservers.conf")
+        self.config.update(self.__read_config_file("/etc/vservers/%s.conf" %
+                                                   self.name))
+        self.flags = 0
+        flags = self.config["S_FLAGS"].split(" ")
+        if "lock" in flags:
+            self.flags |= FLAGS_LOCK
+        if "nproc" in flags:
+            self.flags |= FLAGS_NPROC
+        self.remove_caps = ~CAP_SAFE
+        print "%x %x" % (self.flags, ~self.remove_caps)
+
+    config_var_re = re.compile(r"^ *([A-Z_]+)=(.*)\n?$", re.MULTILINE)
+
+    def __read_config_file(self, filename):
+
+        f = open(filename, "r")
+        data = f.read()
+        f.close()
+        config = {}
+        for m in self.config_var_re.finditer(data):
+            (key, val) = m.groups()
+            config[key] = val.strip('"')
+        return config
+
+    def open(self, filename, mode = "r"):
+
+        (sendsock, recvsock) = passfdimpl.socketpair()
+        child_pid = os.fork()
+        if child_pid == 0:
+            try:
+                # child process
+                os.chroot("%s/%s" % (VROOTDIR, self.name))
+                f = open(filename, mode)
+                passfdimpl.sendmsg(f.fileno(), sendsock)
+                os._exit(0)
+            except EnvironmentError, ex:
+                (result, errmsg) = (ex.errno, ex.strerror)
+            except Exception, ex:
+                (result, errmsg) = (255, str(ex))
+            os.write(sendsock, errmsg)
+            os._exit(result)
+
+        # parent process
+
+        # XXX - need this since a lambda can't raise an exception
+        def __throw(ex):
+            raise ex
+
+        os.close(sendsock)
+        throw = lambda : __throw(Exception(errmsg))
+        while True:
+            try:
+                (pid, status) = os.waitpid(child_pid, 0)
+                if os.WIFEXITED(status):
+                    result = os.WEXITSTATUS(status)
+                    if result != 255:
+                        errmsg = os.strerror(result)
+                        throw = lambda : __throw(IOError(result, errmsg))
+                    else:
+                        errmsg = "unexpected exception in child"
+                else:
+                    result = -1
+                    errmsg = "child killed"
+                break
+            except OSError, ex:
+                if ex.errno != errno.EINTR:
+                    os.close(recvsock)
+                    raise ex
+        fcntl.fcntl(recvsock, fcntl.F_SETFL, os.O_NONBLOCK)
+        try:
+            (fd, errmsg) = passfdimpl.recvmsg(recvsock)
+        except OSError, ex:
+            if ex.errno != errno.EAGAIN:
+                throw = lambda : __throw(ex)
+            fd = 0
+        os.close(recvsock)
+        if not fd:
+            throw()
+
+        return os.fdopen(fd)
diff --git a/python/vserverimpl.c b/python/vserverimpl.c
new file mode 100644 (file)
index 0000000..ecfad20
--- /dev/null
@@ -0,0 +1,64 @@
+/* Copyright 2005 Princeton University
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met: 
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+      
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+      
+    * Neither the name of the copyright holder nor the names of its
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+      
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PRINCETON
+UNIVERSITY OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
+WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. 
+
+*/
+
+#include <Python.h>
+
+#include "compat.h"
+#include "vserver.h"
+
+static PyObject *
+vserver_chcontext(PyObject *self, PyObject *args)
+{
+  unsigned  xid;
+  unsigned  caps_remove = 0;
+
+  if (!PyArg_ParseTuple(args, "I|I", &xid, &caps_remove))
+    return NULL;
+
+  if (vc_new_s_context(xid, caps_remove, 0) < 0)
+    return PyErr_SetFromErrno(PyExc_OSError);
+
+  return Py_None;
+}
+
+static PyMethodDef  methods[] = {
+  { "chcontext", vserver_chcontext, METH_VARARGS,
+    "Change to the given vserver context" },
+  { NULL, NULL, 0, NULL }
+};
+
+PyMODINIT_FUNC
+initvserverimpl(void)
+{
+  Py_InitModule("vserverimpl", methods);
+}