From: Steve Muir Date: Fri, 20 May 2005 21:45:19 +0000 (+0000) Subject: Beginnings of vserver module to support manipulation of vservers without X-Git-Tag: after-util-vserver-0_30_208-revert~189 X-Git-Url: http://git.onelab.eu/?p=util-vserver.git;a=commitdiff_plain;h=471f8ae097d6c209b6cca044534aae586d514c00 Beginnings of vserver module to support manipulation of vservers without jumping through shell hoops --- diff --git a/python/Makefile b/python/Makefile new file mode 100644 index 0000000..3b8879d --- /dev/null +++ b/python/Makefile @@ -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 index 0000000..feeb026 --- /dev/null +++ b/python/vserver.py @@ -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 index 0000000..ecfad20 --- /dev/null +++ b/python/vserverimpl.c @@ -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 + +#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); +}