diff options
Diffstat (limited to 'libmount/python/pylibmount.c')
-rw-r--r-- | libmount/python/pylibmount.c | 303 |
1 files changed, 303 insertions, 0 deletions
diff --git a/libmount/python/pylibmount.c b/libmount/python/pylibmount.c new file mode 100644 index 0000000..a2e1286 --- /dev/null +++ b/libmount/python/pylibmount.c @@ -0,0 +1,303 @@ +/* + * Python bindings for the libmount library. + * + * Copyright (C) 2013, Red Hat, Inc. All rights reserved. + * Written by Ondrej Oprala and Karel Zak + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this file; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#include "pylibmount.h" + +/* Libmount-specific Exception class */ +PyObject *LibmountError; +int pylibmount_debug_mask; + +PyObject *UL_IncRef(void *killme) +{ + Py_INCREF(killme); + return killme; +} + +void PyFree(void *o) +{ +#if PY_MAJOR_VERSION >= 3 + Py_TYPE(o)->tp_free((PyObject *)o); +#else + ((PyObject *)o)->ob_type->tp_free((PyObject *)o); +#endif +} + +/* Demultiplexer for various possible error conditions across the libmount library */ +void *UL_RaiseExc(int e) +{ + /* TODO: Do we need to deal with -1/1? */ + switch (e) { + case ENOMEM: + PyErr_SetString(PyExc_MemoryError, strerror(e)); + break; + case EINVAL: + PyErr_SetString(PyExc_TypeError, strerror(e)); + break; + /* libmount-specific errors */ + case MNT_ERR_APPLYFLAGS: + PyErr_SetString(LibmountError, "Failed to apply MS_PROPAGATION flags"); + break; + case MNT_ERR_MOUNTOPT: + PyErr_SetString(LibmountError, "Failed to parse/use userspace mount options"); + break; + case MNT_ERR_NOFSTAB: + PyErr_SetString(LibmountError, "Failed to detect filesystem type"); + break; + case MNT_ERR_NOFSTYPE: + PyErr_SetString(LibmountError, "Required mount source undefined"); + break; + case MNT_ERR_NOSOURCE: + PyErr_SetString(LibmountError, "Loopdev setup failed"); + break; + case MNT_ERR_AMBIFS: + PyErr_SetString(LibmountError, "Libblkid detected more filesystems on the device"); + break; + /* some other errno */ + default: + PyErr_SetString(PyExc_Exception, strerror(e)); + break; + } + return NULL; +} + +/* + * General functions + */ +PyObject *PyObjectResultInt(int i) +{ + PyObject *result = Py_BuildValue("i", i); + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; +} + +PyObject *PyObjectResultStr(const char *s) +{ + PyObject *result; + if (!s) + /* TODO: maybe lie about it and return "": + * which would allow for + * fs = libmount.Fs() + * fs.comment += "comment" + return Py_BuildValue("s", ""); */ + Py_RETURN_NONE; + result = Py_BuildValue("s", s); + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; +} + +/* wrapper around a common use case for PyUnicode_AsASCIIString() */ +char *pystos(PyObject *pys) +{ +#if PY_MAJOR_VERSION >= 3 + if (!PyUnicode_Check(pys)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (char *)PyUnicode_1BYTE_DATA(pys); +#else + if (!PyString_Check(pys)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyString_AsString(pys); +#endif +} + +/* + * the libmount module + */ +#define PYLIBMOUNT_DESC \ + "Python API for the util-linux libmount library.\n\n" \ + "Please note that none of the classes' attributes may be deleted.\n" \ + "This is not a complete mapping to the libmount C API, nor is it\n" \ + "attempting to be one.\n" "Iterator functions only allow forward\n" \ + "iteration for now. Context.get_{user_,}mflags() differs from the C API\n" \ + "and returns the flags directly. Fs.get_tag() differs from the C API\n" \ + "and returns a (tag, value) tuple. Every attribute is \"filtered\"" \ + "through appropriate getters/setters, no values are set directly." + + +struct module_state { + PyObject *error; +}; + +#if PY_MAJOR_VERSION >= 3 +#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m)) +#else +#define GETSTATE(m) (&_state) +static struct module_state _state; +#endif + +static PyObject * +error_out(PyObject *m __attribute__((unused))) { + struct module_state *st = GETSTATE(m); + PyErr_SetString(st->error, "something bad happened"); + return NULL; +} + +static PyMethodDef pylibmount_methods[] = { + {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL}, + {NULL, NULL} +}; + +#if PY_MAJOR_VERSION >= 3 + +static int pylibmount_traverse(PyObject *m, visitproc visit, void *arg) { + Py_VISIT(GETSTATE(m)->error); + return 0; +} + +static int pylibmount_clear(PyObject *m) { + Py_CLEAR(GETSTATE(m)->error); + return 0; +} + +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "pylibmount", + NULL, + sizeof(struct module_state), + pylibmount_methods, + NULL, + pylibmount_traverse, + pylibmount_clear, + NULL +}; +#define INITERROR return NULL +PyObject * PyInit_pylibmount(void); +PyObject * PyInit_pylibmount(void) +#else +#define INITERROR return +# ifndef PyMODINIT_FUNC +# define PyMODINIT_FUNC void +# endif +PyMODINIT_FUNC initpylibmount(void); +PyMODINIT_FUNC initpylibmount(void) +#endif +{ +#if PY_MAJOR_VERSION >= 3 + PyObject *m = PyModule_Create(&moduledef); +#else + PyObject *m = Py_InitModule3("pylibmount", pylibmount_methods, PYLIBMOUNT_DESC); +#endif + + if (!m) + INITERROR; + /* + * init debug stuff + */ + if (!(pylibmount_debug_mask & PYMNT_DEBUG_INIT)) { + char *str = getenv("PYLIBMOUNT_DEBUG"); + + pylibmount_debug_mask = 0; + if (str) + pylibmount_debug_mask = strtoul(str, NULL, 0); + + pylibmount_debug_mask |= PYMNT_DEBUG_INIT; + } + + if (pylibmount_debug_mask && pylibmount_debug_mask != PYMNT_DEBUG_INIT) + DBG(INIT, pymnt_debug("library debug mask: 0x%04x", + pylibmount_debug_mask)); + mnt_init_debug(0); + + /* + * Add module objects + */ + LibmountError = PyErr_NewException("libmount.Error", NULL, NULL); + Py_INCREF(LibmountError); + PyModule_AddObject(m, "Error", (PyObject *)LibmountError); + + FS_AddModuleObject(m); + Table_AddModuleObject(m); +#ifdef __linux__ + Context_AddModuleObject(m); +#endif + + /* + * mount(8) userspace options masks (MNT_MAP_USERSPACE map) + */ + PyModule_AddIntConstant(m, "MNT_MS_COMMENT", MNT_MS_COMMENT); + PyModule_AddIntConstant(m, "MNT_MS_GROUP", MNT_MS_GROUP); + PyModule_AddIntConstant(m, "MNT_MS_HELPER", MNT_MS_HELPER); + PyModule_AddIntConstant(m, "MNT_MS_LOOP", MNT_MS_LOOP); + PyModule_AddIntConstant(m, "MNT_MS_NETDEV", MNT_MS_NETDEV); + PyModule_AddIntConstant(m, "MNT_MS_NOAUTO", MNT_MS_NOAUTO); + PyModule_AddIntConstant(m, "MNT_MS_NOFAIL", MNT_MS_NOFAIL); + PyModule_AddIntConstant(m, "MNT_MS_OFFSET", MNT_MS_OFFSET); + PyModule_AddIntConstant(m, "MNT_MS_OWNER", MNT_MS_OWNER); + PyModule_AddIntConstant(m, "MNT_MS_SIZELIMIT", MNT_MS_SIZELIMIT); + PyModule_AddIntConstant(m, "MNT_MS_ENCRYPTION", MNT_MS_ENCRYPTION); + PyModule_AddIntConstant(m, "MNT_MS_UHELPER", MNT_MS_UHELPER); + PyModule_AddIntConstant(m, "MNT_MS_USER", MNT_MS_USER); + PyModule_AddIntConstant(m, "MNT_MS_USERS", MNT_MS_USERS); + PyModule_AddIntConstant(m, "MNT_MS_XCOMMENT", MNT_MS_XCOMMENT); + + /* + * mount(2) MS_* masks (MNT_MAP_LINUX map) + */ + PyModule_AddIntConstant(m, "MS_BIND", MS_BIND); + PyModule_AddIntConstant(m, "MS_DIRSYNC", MS_DIRSYNC); + PyModule_AddIntConstant(m, "MS_I_VERSION", MS_I_VERSION); + PyModule_AddIntConstant(m, "MS_MANDLOCK", MS_MANDLOCK); + PyModule_AddIntConstant(m, "MS_MGC_MSK", MS_MGC_MSK); + PyModule_AddIntConstant(m, "MS_MGC_VAL", MS_MGC_VAL); + PyModule_AddIntConstant(m, "MS_MOVE", MS_MOVE); + PyModule_AddIntConstant(m, "MS_NOATIME", MS_NOATIME); + PyModule_AddIntConstant(m, "MS_NODEV", MS_NODEV); + PyModule_AddIntConstant(m, "MS_NODIRATIME", MS_NODIRATIME); + PyModule_AddIntConstant(m, "MS_NOEXEC", MS_NOEXEC); + PyModule_AddIntConstant(m, "MS_NOSUID", MS_NOSUID); + PyModule_AddIntConstant(m, "MS_OWNERSECURE", MS_OWNERSECURE); + PyModule_AddIntConstant(m, "MS_PRIVATE", MS_PRIVATE); + PyModule_AddIntConstant(m, "MS_PROPAGATION", MS_PROPAGATION); + PyModule_AddIntConstant(m, "MS_RDONLY", MS_RDONLY); + PyModule_AddIntConstant(m, "MS_REC", MS_REC); + PyModule_AddIntConstant(m, "MS_RELATIME", MS_RELATIME); + PyModule_AddIntConstant(m, "MS_REMOUNT", MS_REMOUNT); + PyModule_AddIntConstant(m, "MS_SECURE", MS_SECURE); + PyModule_AddIntConstant(m, "MS_SHARED", MS_SHARED); + PyModule_AddIntConstant(m, "MS_SILENT", MS_SILENT); + PyModule_AddIntConstant(m, "MS_SLAVE", MS_SLAVE); + PyModule_AddIntConstant(m, "MS_STRICTATIME", MS_STRICTATIME); + PyModule_AddIntConstant(m, "MS_SYNCHRONOUS", MS_SYNCHRONOUS); + PyModule_AddIntConstant(m, "MS_UNBINDABLE", MS_UNBINDABLE); + + /* Will we need these directly? + PyModule_AddIntConstant(m, "MNT_ERR_AMBIFS", MNT_ERR_AMBIFS); + PyModule_AddIntConstant(m, "MNT_ERR_APPLYFLAGS", MNT_ERR_APPLYFLAGS); + PyModule_AddIntConstant(m, "MNT_ERR_LOOPDEV", MNT_ERR_LOOPDEV); + PyModule_AddIntConstant(m, "MNT_ERR_MOUNTOPT", MNT_ERR_MOUNTOPT); + PyModule_AddIntConstant(m, "MNT_ERR_NOFSTAB", MNT_ERR_NOFSTAB); + PyModule_AddIntConstant(m, "MNT_ERR_NOFSTYPE", MNT_ERR_NOFSTYPE); + PyModule_AddIntConstant(m, "MNT_ERR_NOSOURCE", MNT_ERR_NOSOURCE); + */ + + /* Still useful for functions using iterators internally */ + PyModule_AddIntConstant(m, "MNT_ITER_FORWARD", MNT_ITER_FORWARD); + PyModule_AddIntConstant(m, "MNT_ITER_BACKWARD", MNT_ITER_BACKWARD); + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} + |