/* * CORE * Copyright (c)2010-2012 the Boeing Company. * See the LICENSE file included in this distribution. * * author: Tom Goff * * netnsmodule.c * * Python module C bindings providing nsfork and nsexecvp methods for * forking a child process into a new namespace, with nsexecvp executing a * new program using the default search path. * */ #include #include #include #include "netns.h" /* parts taken from python/trunk/Modules/posixmodule.c */ static void free_string_array(char **array, Py_ssize_t count) { Py_ssize_t i; for (i = 0; i < count; i++) PyMem_Free(array[i]); PyMem_DEL(array); } static PyObject *netns_nsexecvp(PyObject *self, PyObject *args) { pid_t pid; char **argv; Py_ssize_t i, argc; PyObject *(*getitem)(PyObject *, Py_ssize_t); /* args should be a list or tuple of strings */ if (PyList_Check(args)) { argc = PyList_Size(args); getitem = PyList_GetItem; } else if (PyTuple_Check(args)) { argc = PyTuple_Size(args); getitem = PyTuple_GetItem; } else { PyErr_SetString(PyExc_TypeError, "netns_nsexecvp() args must be a tuple or list"); return NULL; } argv = PyMem_NEW(char *, argc + 1); if (argv == NULL) return PyErr_NoMemory(); for (i = 0; i < argc; i++) { if (!PyArg_Parse((*getitem)(args, i), "et", Py_FileSystemDefaultEncoding, &argv[i])) { free_string_array(argv, i); PyErr_SetString(PyExc_TypeError, "netns_nsexecvp() args must contain only strings"); return NULL; } } argv[argc] = NULL; pid = nsexecvp(argv); free_string_array(argv, argc); if (pid < 0) return PyErr_SetFromErrno(PyExc_OSError); else #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(pid); #else return PyInt_FromLong(pid); #endif } static PyObject *netns_nsfork(PyObject *self, PyObject *args) { int flags; pid_t pid; if (!PyArg_ParseTuple(args, "i", &flags)) return NULL; pid = nsfork(flags); if (pid < 0) return PyErr_SetFromErrno(PyExc_OSError); if (pid == 0) /* child */ PyOS_AfterFork(); #if PY_MAJOR_VERSION >= 3 return PyLong_FromLong(pid); #else return PyInt_FromLong(pid); #endif } static PyMethodDef netns_methods[] = { {"nsfork", netns_nsfork, METH_VARARGS, "nsfork(cloneflags) -> int\n\n" "Fork a child process into a new namespace using the Linux clone()\n" "system call.\n\n" "cloneflags: additional flags passed to clone()"}, {"nsexecvp", netns_nsexecvp, METH_VARARGS, "nsexecvp(args...) -> int\n\n" "Fork a child process into a new namespace using the Linux clone()\n" "system call and have the child execute a new program using the\n" "default search path.\n\n" "args: the executable file name followed by command arguments"}, {NULL, NULL, 0, NULL}, }; #if PY_MAJOR_VERSION >= 3 #define INITERROR return NULL static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "netns", /* m_name */ "netns module", /* m_doc */ -1, /* m_size */ netns_methods, /* m_methods */ NULL, /* m_reload */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; #else #define INITERROR return #endif PyMODINIT_FUNC initnetns(void) { PyObject *m; #if PY_MAJOR_VERSION >= 3 m = PyModule_Create(&moduledef); #else m = Py_InitModule("netns", netns_methods); #endif if (m == NULL) INITERROR; #define MODADDINT(x) \ do { \ PyObject *tmp = Py_BuildValue("i", x); \ if (tmp) \ { \ Py_INCREF(tmp); \ PyModule_AddObject(m, #x, tmp); \ } \ } while (0) MODADDINT(CLONE_VFORK); #undef MODADDINT INITERROR; }