| /* |
| * 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 |
| } |
| |