From 813683a3525d0530968698b92cd604b1f49b26a7 Mon Sep 17 00:00:00 2001 From: Ondrej Oprala Date: Mon, 19 Aug 2013 15:00:15 +0200 Subject: pylibmount: basic code [kzak@redhat.com: - split to more patches - split to more .c files] Signed-off-by: Ondrej Oprala Signed-off-by: Karel Zak --- libmount/python/Makemodule.am | 9 +- libmount/python/context.c | 1240 +++++++++++++++++++++++++++++++++++++++++ libmount/python/fs.c | 790 ++++++++++++++++++++++++++ libmount/python/pylibmount.c | 205 +++++++ libmount/python/pylibmount.h | 78 +++ libmount/python/tab.c | 725 ++++++++++++++++++++++++ 6 files changed, 3045 insertions(+), 2 deletions(-) create mode 100644 libmount/python/context.c create mode 100644 libmount/python/fs.c create mode 100644 libmount/python/pylibmount.c create mode 100644 libmount/python/pylibmount.h create mode 100644 libmount/python/tab.c (limited to 'libmount/python') diff --git a/libmount/python/Makemodule.am b/libmount/python/Makemodule.am index 30946d635..bafa8ada8 100644 --- a/libmount/python/Makemodule.am +++ b/libmount/python/Makemodule.am @@ -2,8 +2,13 @@ if BUILD_PYLIBMOUNT pyexec_LTLIBRARIES += pylibmount.la -pylibmount_la_SOURCES = - +pylibmount_la_SOURCES = \ + libmount/python/pylibmount.c \ + libmount/python/pylibmount.h \ + libmount/python/fs.c \ + libmount/python/tab.c \ + libmount/python/context.c + pylibmount_la_LIBADD = libmount.la -lpython$(PYTHON_VERSION) pylibmount_la_CFLAGS = \ diff --git a/libmount/python/context.c b/libmount/python/context.c new file mode 100644 index 000000000..5df84ac9e --- /dev/null +++ b/libmount/python/context.c @@ -0,0 +1,1240 @@ +/* + * 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" + +static PyMemberDef Cxt_members[] = { + {NULL} +}; + +static PyObject *Cxt_set_tables_errcb(CxtObject *self, PyObject *func, void *closure __attribute__((unused))) +{ + if (!func) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return NULL; + } + if (!PyCallable_Check(func)) + return NULL; + else { + PyObject *tmp = self->table_errcb; + Py_INCREF(func); + self->table_errcb = func; + Py_XDECREF(tmp); + } + return UL_IncRef(self); +} + +static void Cxt_dealloc(CxtObject *self) +{ + if (!self->cxt) /* if init fails */ + return; + + if (!(self->cxt->flags & MNT_FL_EXTERN_FS)) { + if (self->cxt->fs && self->cxt->fs->userdata) + Py_DECREF(self->cxt->fs->userdata); + else { + mnt_free_fs(self->cxt->fs); + } + self->cxt->fs = NULL; + } + + if (self->cxt->fstab && !(self->cxt->flags & MNT_FL_EXTERN_FSTAB)) { + if (self->cxt->fstab->userdata) + Py_DECREF(self->cxt->fstab->userdata); + else { + pymnt_free_table(self->cxt->fstab); + } + self->cxt->fstab = NULL; + } + if (self->cxt->mtab) { + if (self->cxt->mtab->userdata) + Py_DECREF(self->cxt->mtab->userdata); + else { + pymnt_free_table(self->cxt->mtab); + } + self->cxt->mtab = NULL; + } + mnt_free_context(self->cxt); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject *Cxt_new(PyTypeObject *type, PyObject *args __attribute__((unused)), + PyObject *kwds __attribute__((unused))) +{ + CxtObject *self = (CxtObject*)type->tp_alloc(type, 0); + if (self) { + self->cxt = NULL; + self->table_errcb = NULL; + } + + return (PyObject *)self; +} +/* Note there is no pointer to encapsulating object needed here, since Cxt is on top of the Context(Table(Filesystem)) hierarchy */ +#define Cxt_HELP "Cxt(source=None, target=None, fstype=None, options=None, mflags=0, fstype_pattern=None, options_pattern=None, fs=None, fstab=None, optsmode=0, syscall_status=1)" +static int Cxt_init(CxtObject *self, PyObject *args, PyObject *kwds) +{ + char *source = NULL, *target = NULL, *fstype = NULL; + char *options = NULL, *fstype_pattern = NULL, *options_pattern = NULL; + unsigned long mflags = 0; + int optsmode = 0, syscall_status = 1; + FsObject *fs = NULL; + TabObject *fstab = NULL; + int rc = 0; + char *kwlist[] = {"source", "target", "fstype", "options", "mflags", "fstype_pattern", + "options_pattern", "fs", "fstab", "optsmode", "syscall_status"}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssskssO!O!ii", kwlist, &source, &target, &fstype, &options, &mflags, &fstype_pattern, &options_pattern, &FsType, &fs, &TabType, &fstab, &optsmode, &syscall_status)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + if (self->cxt) + mnt_free_context(self->cxt); + + if ((self->cxt = mnt_new_context())) { + if (source) { + if ((rc = mnt_context_set_source(self->cxt, source))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (target) { + if ((rc = mnt_context_set_target(self->cxt, target))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (fstype) { + if ((rc = mnt_context_set_fstype(self->cxt, fstype))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (options) { + if ((rc = mnt_context_set_options(self->cxt, options))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (fstype_pattern) { + if ((rc = mnt_context_set_fstype_pattern(self->cxt, fstype_pattern))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (options_pattern) { + if ((rc = mnt_context_set_options_pattern(self->cxt, options_pattern))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (fs) { + if ((rc = mnt_context_set_fs(self->cxt, fs->fs))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (fstab) { + if ((rc = mnt_context_set_fstab(self->cxt, fstab->tab))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (optsmode) { + if ((rc = mnt_context_set_optsmode(self->cxt, optsmode))) { + UL_RaiseExc(-rc); + return -1; + } + } + if (syscall_status) { + if ((rc = mnt_context_set_syscall_status(self->cxt, syscall_status))) { + UL_RaiseExc(-rc); + return -1; + } + } + mnt_context_set_mflags(self->cxt, mflags); + mnt_context_set_optsmode(self->cxt, optsmode); + mnt_context_set_syscall_status(self->cxt, syscall_status); + } + else { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return -1; + } + self->cxt->table_errcb = pymnt_table_parser_errcb; + return 0; +} + +#define Cxt_enable_fake_HELP "enable_fake(enable)\n\n\ +Enable/disable fake mounting (see mount(8) man page, option -f).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_fake(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_fake(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_force_HELP "enable_force(enable)\n\n\ +Enable/disable force umounting (see umount(8) man page, option -f).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_force(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_force(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_lazy_HELP "enable_lazy(enable)\n\n\ +Enable/disable lazy umount (see umount(8) man page, option -l).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_lazy(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_lazy(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_loopdel_HELP "enable_loopdel(enable)\n\n\ +Enable/disable loop delete (destroy) after umount (see umount(8), option -d)\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_loopdel(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_loopdel(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_rdonly_umount_HELP "enable_rdonly_umount(enable)\n\n\ +Enable/disable read-only remount on failed umount(2)\n\ +(see umount(8) man page, option -r).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_rdonly_umount(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_rdonly_umount(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_sloppy_HELP "enable_sloppy(enable)\n\n\ +Set/unset sloppy mounting (see mount(8) man page, option -s).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_sloppy(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_sloppy(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_verbose_HELP "enable_verbose(enable)\n\n\ +Enable/disable verbose output (TODO: not implemented yet)\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_verbose(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_verbose(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_enable_fork_HELP "enable_fork(enable)\n\n\ +Enable/disable fork(2) call in Cxt.next_mount()(not yet implemented) (see mount(8) man\n\ +page, option -F).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_enable_fork(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int enable; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_enable_fork(self->cxt, enable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_disable_canonicalize_HELP "disable_canonicalize(disable)\n\n\ +Enable/disable paths canonicalization and tags evaluation. The libmount context\n\ +canonicalies paths when search in fstab and when prepare source and target paths\n\ +for mount(2) syscall.\n\ +\n\ +This fuction has effect to the private (within context) fstab instance only\n\ +(see Cxt.fstab).\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_disable_canonicalize(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int disable; + char *kwlist[] = {"disable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &disable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_disable_canonicalize(self->cxt, disable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_disable_helpers_HELP "disable_helpers(disable)\n\n\ +Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_disable_helpers(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int disable; + char *kwlist[] = {"disable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &disable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_disable_helpers(self->cxt, disable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_disable_mtab_HELP "disable_mtab(disable)\n\n\ +Disable/enable mtab update (see mount(8) man page, option -n).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_disable_mtab(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int disable; + char *kwlist[] = {"disable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &disable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_disable_mtab(self->cxt, disable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_disable_swapmatch_HELP "disable_swapmatch(disable)\n\n\ +Disable/enable swap between source and target for mount(8) if only one path\n\ +is specified.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_disable_swapmatch(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int disable; + char *kwlist[] = {"disable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &disable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_disable_swapmatch(self->cxt, disable)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +static int Cxt_set_source(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *source; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(source = pystos(value))) + return -1; + + rc = mnt_context_set_source(self->cxt, source); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_mountdata(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *mountdata; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(mountdata = pystos(value))) + return -1; + + rc = mnt_context_set_mountdata(self->cxt, mountdata); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_target(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char * target; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(target = pystos(value))) + return -1; + + rc = mnt_context_set_target(self->cxt, target); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_fstype(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char * fstype; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(fstype = pystos(value))) + return -1; + + rc = mnt_context_set_fstype(self->cxt, fstype); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_options(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char * options; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(options = pystos(value))) + return -1; + + rc = mnt_context_set_options(self->cxt, options); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_fstype_pattern(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char * fstype_pattern; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(fstype_pattern = pystos(value))) + return -1; + + rc = mnt_context_set_fstype_pattern(self->cxt, fstype_pattern); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_options_pattern(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char * options_pattern; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(options_pattern = pystos(value))) + return -1; + + rc = mnt_context_set_options_pattern(self->cxt, options_pattern); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static int Cxt_set_fs(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + FsObject *fs; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!PyArg_Parse(value, "O!", &FsType, &fs)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + Py_INCREF(fs); + if (self->cxt->fs) + Py_XDECREF(self->cxt->fs->userdata); + return mnt_context_set_fs(self->cxt, fs->fs); +} + +static int Cxt_set_fstab(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + TabObject *fstab; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!PyArg_Parse(value, "O!", &TabType, &fstab)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + Py_INCREF(fstab); + if (self->cxt->fstab) + Py_XDECREF(self->cxt->fstab->userdata); + return mnt_context_set_fstab(self->cxt, fstab->tab); +} + +static int Cxt_set_optsmode(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + int optsmode; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + optsmode = PyInt_AsLong(value); + return mnt_context_set_optsmode(self->cxt, optsmode); +} + +static int Cxt_set_syscall_status(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + int syscall_status; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + syscall_status = PyInt_AsLong(value); + return mnt_context_set_syscall_status(self->cxt, syscall_status); +} + +static int Cxt_set_user_mflags(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + unsigned long flags; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + flags = PyLong_AsUnsignedLong(value); + return mnt_context_set_mflags(self->cxt, flags); + +} + +static int Cxt_set_mflags(CxtObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + unsigned long flags; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + flags = PyLong_AsUnsignedLong(value); + return mnt_context_set_mflags(self->cxt, flags); +} +/* returns a flags integer (behaviour differs from C API) */ +static PyObject *Cxt_get_mflags(CxtObject *self) +{ + unsigned long flags; + PyObject *result; + mnt_context_get_mflags(self->cxt, &flags); + result = Py_BuildValue("k", flags); + + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; + +} +/* returns a flags integer (behaviour differs from C API) */ +static PyObject *Cxt_get_user_mflags(CxtObject *self) +{ + unsigned long flags; + PyObject *result; + mnt_context_get_user_mflags(self->cxt, &flags); + result = Py_BuildValue("k", flags); + + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; + +} +#define Cxt_reset_status_HELP "reset_status()\n\n\ +Resets mount(2) and mount.type statuses, so Cxt.do_mount() or\n\ +Cxt.do_umount() could be again called with the same settings.\n\ +\n\ +BE CAREFUL -- after this soft reset the libmount will NOT parse mount\n\ +options, evaluate permissions or apply stuff from fstab.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_reset_status(CxtObject *self) +{ + int rc; + return (rc = mnt_context_reset_status(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_is_fake_HELP "is_fake()\n\n\ +Returns True if fake flag is enabled or False" +static PyObject *Cxt_is_fake(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_fake(self->cxt)); +} + +#define Cxt_is_force_HELP "is_force()\n\n\ +Returns True if force umounting flag is enabled or False" +static PyObject *Cxt_is_force(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_force(self->cxt)); +} + +#define Cxt_is_lazy_HELP "is_lazy()\n\n\ +Returns True if lazy umount is enabled or False" +static PyObject *Cxt_is_lazy(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_lazy(self->cxt)); +} + +#define Cxt_is_nomtab_HELP "is_nomtab()\n\n\ +Returns True if no-mtab is enabled or False" +static PyObject *Cxt_is_nomtab(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_nomtab(self->cxt)); +} + +#define Cxt_is_rdonly_umount_HELP "is_rdonly_umount()\n\n\ +Enable/disable read-only remount on failed umount(2)\n\ +(see umount(8) man page, option -r).\n\ +\n\ +Returns self on success, raises an exception in case of error." +static PyObject *Cxt_is_rdonly_umount(CxtObject *self) +{ + int rc; + return (rc = mnt_context_is_rdonly_umount(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_is_restricted_HELP "is_restricted()\n\n\ +Returns False for unrestricted mount (user is root), or True for non-root mounts" +static PyObject *Cxt_is_restricted(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_restricted(self->cxt)); +} + +#define Cxt_is_sloppy_HELP "is_sloppy()\n\n\ +Returns True if sloppy flag is enabled or False" +static PyObject *Cxt_is_sloppy(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_sloppy(self->cxt)); +} + +#define Cxt_is_verbose_HELP "is_verbose()\n\n\ +Returns True if verbose flag is enabled or False" +static PyObject *Cxt_is_verbose(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_verbose(self->cxt)); +} +#define Cxt_is_fs_mounted_HELP "is_fs_mounted(fs, mounted)\n\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_is_fs_mounted(CxtObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"fs", "mounted", NULL}; + FsObject *fs; + int mounted; + if (PyArg_ParseTupleAndKeywords(args, kwds, "O!i", kwlist, &FsType, &fs, &mounted)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_context_is_fs_mounted(self->cxt, fs->fs, &mounted)); +} + +#define Cxt_is_child_HELP "is_child()\n\n\ +Returns True if mount -F enabled and the current context is child, or False" +static PyObject *Cxt_is_child(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_child(self->cxt)); +} + +#define Cxt_is_fork_HELP "is_fork()\n\n\ +Returns True if fork (mount -F) is enabled or False" +static PyObject *Cxt_is_fork(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_fork(self->cxt)); +} + +#define Cxt_is_parent_HELP "is_parent()\n\n\ +Returns True if mount -F enabled and the current context is parent, or False" +static PyObject *Cxt_is_parent(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_parent(self->cxt)); +} + +#define Cxt_is_loopdel_HELP "is_loopdel()\n\n\ +Returns True if loop device should be deleted after umount (umount -d) or False." +static PyObject *Cxt_is_loopdel(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_loopdel(self->cxt)); +} + +#define Cxt_is_nocanonicalize_HELP "is_nocanonicalize()\n\n\ +Returns True if no-canonicalize mode enabled or False." +static PyObject *Cxt_is_nocanonicalize(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_nocanonicalize(self->cxt)); +} + +#define Cxt_is_nohelpers_HELP "is_nohelpers()\n\n\ +Returns True if helpers are disabled (mount -i) or False." +static PyObject *Cxt_is_nohelpers(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_nohelpers(self->cxt)); +} + +#define Cxt_syscall_called_HELP "syscall_called()\n\n\ +Returns True if mount(2) syscall has been called, or False." +static PyObject *Cxt_syscall_called(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_syscall_called(self->cxt)); +} + +#define Cxt_is_swapmatch_HELP "is_swapmatch()\n\n\ +Returns True if swap between source and target is allowed (default is True) or False." +static PyObject *Cxt_is_swapmatch(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_is_swapmatch(self->cxt)); +} + +#define Cxt_tab_applied_HELP "tab_applied()\n\n\ +Returns True if fstab (or mtab) has been applied to the context, False otherwise." +static PyObject *Cxt_tab_applied(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_tab_applied(self->cxt)); +} + +#define Cxt_apply_fstab_HELP "apply_fstab()\n\n\ +This function is optional.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_apply_fstab(CxtObject *self) +{ + int rc; + if (!self->cxt->fs) { + PyErr_SetString(PyExc_AssertionError, NOFS_ERR); + return NULL; + } + return (rc = mnt_context_apply_fstab(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_helper_executed_HELP "helper_executed()\n\n\ +Returns True if mount.type helper has been executed, or False." +static PyObject *Cxt_helper_executed(CxtObject *self) +{ + return PyBool_FromLong(mnt_context_helper_executed(self->cxt)); +} + +static PyObject *Cxt_get_source(CxtObject *self) +{ + return PyObjectResultStr(mnt_context_get_source(self->cxt)); +} + +static PyObject *Cxt_get_target(CxtObject *self) +{ + return PyObjectResultStr(mnt_context_get_target(self->cxt)); +} + +static PyObject *Cxt_get_options(CxtObject *self) +{ + return PyObjectResultStr(mnt_context_get_options(self->cxt)); +} + +static PyObject *Cxt_get_fstype(CxtObject *self) +{ + return PyObjectResultStr(mnt_context_get_fstype(self->cxt)); +} + +static PyObject *Cxt_get_fs(CxtObject *self) +{ + return PyObjectResultFs(mnt_context_get_fs(self->cxt)); +} + +static PyObject *Cxt_get_fstab(CxtObject *self) +{ + struct libmnt_table *tab = NULL; + mnt_context_get_fstab(self->cxt, &tab); + if (!tab) + return NULL; + return PyObjectResultTab(tab); +} + +static PyObject *Cxt_get_mtab(CxtObject *self) +{ + struct libmnt_table *tab = NULL; + mnt_context_get_mtab(self->cxt, &tab); + return PyObjectResultTab(tab); +} +#define Cxt_get_table_HELP "get_table(filename)\n\n\ +This function allocates a new table and parses the file. The parser error\n\ +callback and cache for tags and paths is set according to the cxt setting.\n\ +See also Tab.parse_file().\n\ +\n\ +It's strongly recommended to use Cxt.mtab and\n\ +Cxt.fstab for mtab and fstab files. These setters\n\ +do not care about LIBMOUNT_* env.variables and do not merge userspace\n\ +options.\n\ +\n\ +The getters return a new reference to the result.\n\ +\n\ +Returns self or raises an exception in case of an error." +/* output differs from the C API */ +static PyObject *Cxt_get_table(CxtObject *self, PyObject *args, PyObject *kwds) +{ + char *filename; + struct libmnt_table *tab = NULL; + char *kwlist[] = {"filename", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filename)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + mnt_context_get_table(self->cxt, filename, &tab); + return PyObjectResultTab(tab); +} + +static PyObject *Cxt_get_optsmode(CxtObject *self) +{ + return PyObjectResultInt(mnt_context_get_optsmode(self->cxt)); +} + +static PyObject *Cxt_get_status(CxtObject *self) +{ + return PyObjectResultInt(mnt_context_get_status(self->cxt)); +} + +static PyObject *Cxt_get_syscall_errno(CxtObject *self) +{ + return PyObjectResultInt(mnt_context_get_syscall_errno(self->cxt)); +} + +#define Cxt_do_mount_HELP "do_mount()\n\n\ +Call mount(2) or mount.type helper. Unnecessary for Cxt.mount().\n\ +\n\ +Note that this function could be called only once. If you want to mount\n\ +another source or target than you have to call Cxt.reset_context().\n\ +\n\ +If you want to call mount(2) for the same source and target with a different\n\ +mount flags or fstype then call Cxt.reset_status() and then try\n\ +again Cxt.do_mount().\n\ +\n\ +WARNING: non-zero return code does not mean that mount(2) syscall or\n\ +mount.type helper wasn't successfully called.\n\ +\n\ +Check Cxt.status after error!\n\ +\n\ +Returns self on success\n\ +or an exception in case of other errors." +static PyObject *Cxt_do_mount(CxtObject *self) +{ + int rc; + if (!self->cxt->fs) { + PyErr_SetString(PyExc_AssertionError, NOFS_ERR); + return NULL; + } + return (rc = mnt_context_do_mount(self->cxt)) ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self); +} + +#define Cxt_do_umount_HELP "do_umount()\n\n\ +Umount filesystem by umount(2) or fork()+exec(/sbin/umount.type).\n\ +Unnecessary for Cxt.umount().\n\ +\n\ +See also Cxt.disable_helpers().\n\ +\n\ +WARNING: non-zero return code does not mean that umount(2) syscall or\n\ +umount.type helper wasn't successfully called.\n\ +\n\ +Check Cxt.status after error!\n\ +\n\ +Returns self on success\n\ +or an exception in case of other errors." +static PyObject *Cxt_do_umount(CxtObject *self) +{ + int rc; + return (rc = mnt_context_do_umount(self->cxt)) ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self); +} + +#define Cxt_mount_HELP "mount()\n\n\ +High-level, mounts filesystem by mount(2) or fork()+exec(/sbin/mount.type).\n\ +\n\ +This is similar to:\n\ +\n\ +Cxt.prepare_mount();\n\ +Cxt.do_mount();\n\ +Cxt.finalize_mount();\n\ +\n\ +See also Cxt.disable_helper().\n\ +\n\ +Note that this function could be called only once. If you want to mount with\n\ +different setting than you have to call Cxt.reset_context(). It's NOT enough\n\ +to call Cxt.reset_status() if you want call this function more than\n\ +once, whole context has to be reset.\n\ +\n\ +WARNING: non-zero return code does not mean that mount(2) syscall or\n\ +mount.type helper wasn't successfully called.\n\ +\n\ +Check Cxt.status after error!\n\ +\n\ +Returns self on success\n\ +or an exception in case of other errors." +static PyObject *Cxt_mount(CxtObject *self) +{ + int rc; + if (!self->cxt->fs) { + PyErr_SetString(PyExc_AssertionError, NOFS_ERR); + return NULL; + } + return (rc = mnt_context_mount(self->cxt)) ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self); +} + +#define Cxt_umount_HELP "umount()\n\n\ +High-level, umounts filesystem by umount(2) or fork()+exec(/sbin/umount.type).\n\ +\n\ +This is similar to:\n\ +\n\ +Cxt.prepare_umount();\n\ +Cxt.do_umount();\n\ +Cxt.finalize_umount();\n\ +\n\ +See also Cxt.disable_helpers().\n\ +\n\ +WARNING: non-zero return code does not mean that umount(2) syscall or\n\ +umount.type helper wasn't successfully called.\n\ +\n\ +Check Cxt.status after error!\n\ +\n\ +Returns self on success\n\ +or an exception in case of other errors." +static PyObject *Cxt_umount(CxtObject *self) +{ + int rc; + return (rc = mnt_context_umount(self->cxt)) ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self); +} + +#define Cxt_finalize_mount_HELP "finalize_mount()\n\n\ +Mtab update, etc. Unnecessary for Cxt.mount(), but should be called\n\ +after Cxt.do_mount(). See also Cxt.syscall_status.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_finalize_mount(CxtObject *self) +{ + int rc; + if (!self->cxt->fs) { + PyErr_SetString(PyExc_AssertionError, NOFS_ERR); + return NULL; + } + return (rc = mnt_context_finalize_mount(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_prepare_umount_HELP "prepare_umount()\n\n\ +Prepare context for umounting, unnecessary for Cxt.umount().\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_prepare_umount(CxtObject *self) +{ + int rc; + return (rc = mnt_context_prepare_umount(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_prepare_mount_HELP "prepare_mount()\n\n\ +Prepare context for mounting, unnecessary for Cxt.mount().\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_prepare_mount(CxtObject *self) +{ + int rc; + if (!self->cxt->fs) { + PyErr_SetString(PyExc_AssertionError, NOFS_ERR); + return NULL; + } + return (rc = mnt_context_prepare_mount(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_finalize_umount_HELP "finalize_umount()\n\n\ +Mtab update, etc. Unnecessary for Cxt.umount(), but should be called\n\ +after Cxt.do_umount(). See also Cxt.syscall_status.\n\ +\n\ +Returns self on success, raises LibmountError if target filesystem not found, or other exception on error." +static PyObject *Cxt_finalize_umount(CxtObject *self) +{ + int rc; + return (rc = mnt_context_finalize_umount(self->cxt)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_find_umount_fs_HELP "find_umount_fs(tgt, pfs)\n\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_find_umount_fs(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + char *kwlist[] = {"tgt", "pfs", NULL}; + char *tgt = NULL; + FsObject *fs; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO!", kwlist, &tgt, &FsType, &fs)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_find_umount_fs(self->cxt, tgt, &fs->fs)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_append_options_HELP "append_options(optstr)\n\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_append_options(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + char *kwlist[] = {"optstr", NULL}; + char *optstr = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_append_options(self->cxt, optstr)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_helper_setopt_HELP "helper_setopt(c, arg)\n\n\ +This function applies [u]mount.type command line option (for example parsed\n\ +by getopt or getopt_long) to cxt. All unknown options are ignored and\n\ +then ValueError is raised.\n\ +\n\ +Returns self on success, raises ValueError if c is unknown or other exception in case of an error." +static PyObject *Cxt_helper_setopt(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int c; + char *arg; + char *kwlist[] = {"c", "arg", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "is", kwlist, &c, &arg)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_helper_setopt(self->cxt, c, arg)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Cxt_init_helper_HELP "init_helper(action, flags)\n\n\ +This function infors libmount that used from [u]mount.type helper.\n\ +\n\ +The function also calls Cxt.disable_helpers() to avoid recursive\n\ +mount.type helpers calling. It you really want to call another\n\ +mount.type helper from your helper than you have to explicitly enable this\n\ +feature by:\n\ +\n\ +Cxt.disable_helpers(False);\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Cxt_init_helper(CxtObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + int action, flags; + char *kwlist[] = {"action", "flags", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ii", kwlist, &action, &flags)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_context_init_helper(self->cxt, action, flags)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +static PyGetSetDef Cxt_getseters[] = { + {"tables_errcb", NULL, (setter)Cxt_set_tables_errcb, "error callback function", NULL}, + {"status", (getter)Cxt_get_status, NULL, "status", NULL}, + {"source", (getter)Cxt_get_source, (setter)Cxt_set_source, "source", NULL}, + {"target", (getter)Cxt_get_target, (setter)Cxt_set_target, "target", NULL}, + {"fstype", (getter)Cxt_get_fstype, (setter)Cxt_set_fstype, "fstype", NULL}, + {"options", (getter)Cxt_get_options, (setter)Cxt_set_options, "options", NULL}, + {"mflags", (getter)Cxt_get_mflags, (setter)Cxt_set_mflags, "mflags", NULL}, + {"mountdata", NULL, (setter)Cxt_set_mountdata, "mountdata", NULL}, + {"fstype_pattern", NULL, (setter)Cxt_set_fstype_pattern, "fstype_pattern", NULL}, + {"options_pattern", NULL, (setter)Cxt_set_options_pattern, "options_pattern", NULL}, + {"fs", (getter)Cxt_get_fs, (setter)Cxt_set_fs, "filesystem description (type, mountpoint, device, ...)", NULL}, + {"mtab", (getter)Cxt_get_mtab, NULL, "mtab entries", NULL}, + {"fstab", (getter)Cxt_get_fstab, (setter)Cxt_set_fstab, "fstab (or mtab for some remounts)", NULL}, + {"optsmode", (getter)Cxt_get_optsmode, (setter)Cxt_set_optsmode, "fstab optstr mode MNT_OPTSMODE_{AUTO,FORCE,IGNORE}", NULL}, + {"syscall_errno", (getter)Cxt_get_syscall_errno, (setter)Cxt_set_syscall_status, "1: not_called yet, 0: success, <0: -errno", NULL}, + {"user_mflags", (getter)Cxt_get_user_mflags, (setter)Cxt_set_user_mflags, "user mflags", NULL}, + {NULL} +}; +static PyMethodDef Cxt_methods[] = { + {"get_table", (PyCFunction)Cxt_get_table, METH_VARARGS|METH_KEYWORDS, Cxt_get_table_HELP}, + {"find_umount_fs", (PyCFunction)Cxt_find_umount_fs, METH_VARARGS|METH_KEYWORDS, Cxt_find_umount_fs_HELP}, + {"reset_status", (PyCFunction)Cxt_reset_status, METH_NOARGS, Cxt_reset_status_HELP}, + {"helper_executed", (PyCFunction)Cxt_helper_executed, METH_NOARGS, Cxt_helper_executed_HELP}, + {"init_helper", (PyCFunction)Cxt_init_helper, METH_VARARGS|METH_KEYWORDS, Cxt_init_helper_HELP}, + {"helper_setopt", (PyCFunction)Cxt_helper_setopt, METH_VARARGS|METH_KEYWORDS, Cxt_helper_setopt_HELP}, + {"append_options", (PyCFunction)Cxt_append_options, METH_VARARGS|METH_KEYWORDS, Cxt_append_options_HELP}, + {"apply_fstab", (PyCFunction)Cxt_apply_fstab, METH_NOARGS, Cxt_apply_fstab_HELP}, + {"disable_canonicalize", (PyCFunction)Cxt_disable_canonicalize, METH_VARARGS|METH_KEYWORDS, Cxt_disable_canonicalize_HELP}, + {"disable_helpers", (PyCFunction)Cxt_disable_helpers, METH_VARARGS|METH_KEYWORDS, Cxt_disable_helpers_HELP}, + {"disable_mtab", (PyCFunction)Cxt_disable_mtab, METH_VARARGS|METH_KEYWORDS, Cxt_disable_mtab_HELP}, + {"do_mount", (PyCFunction)Cxt_do_mount, METH_NOARGS, Cxt_do_mount_HELP}, + {"do_umount", (PyCFunction)Cxt_do_umount, METH_NOARGS , Cxt_do_umount_HELP}, + {"enable_fake", (PyCFunction)Cxt_enable_fake, METH_VARARGS|METH_KEYWORDS, Cxt_enable_fake_HELP}, + {"enable_force", (PyCFunction)Cxt_enable_force, METH_VARARGS|METH_KEYWORDS, Cxt_enable_force_HELP}, + {"enable_lazy", (PyCFunction)Cxt_enable_lazy, METH_VARARGS|METH_KEYWORDS, Cxt_enable_lazy_HELP}, + {"enable_loopdel", (PyCFunction)Cxt_enable_loopdel, METH_VARARGS|METH_KEYWORDS, Cxt_enable_loopdel_HELP}, + {"enable_rdonly_umount", (PyCFunction)Cxt_enable_rdonly_umount, METH_VARARGS|METH_KEYWORDS, Cxt_enable_rdonly_umount_HELP}, + {"enable_sloppy", (PyCFunction)Cxt_enable_sloppy, METH_VARARGS|METH_KEYWORDS, Cxt_enable_sloppy_HELP}, + {"enable_verbose", (PyCFunction)Cxt_enable_verbose, METH_VARARGS|METH_KEYWORDS, Cxt_enable_verbose_HELP}, + {"enable_fork", (PyCFunction)Cxt_enable_fork, METH_VARARGS|METH_KEYWORDS, Cxt_enable_fork_HELP}, + {"finalize_mount", (PyCFunction)Cxt_finalize_mount, METH_NOARGS, Cxt_finalize_mount_HELP}, + {"finalize_umount", (PyCFunction)Cxt_finalize_umount, METH_NOARGS, Cxt_finalize_umount_HELP}, + {"is_fake", (PyCFunction)Cxt_is_fake, METH_NOARGS, Cxt_is_fake_HELP}, + {"is_force", (PyCFunction)Cxt_is_force, METH_NOARGS, Cxt_is_force_HELP}, + {"is_fork", (PyCFunction)Cxt_is_fork, METH_NOARGS, Cxt_is_fork_HELP}, + {"is_fs_mounted", (PyCFunction)Cxt_is_fs_mounted, METH_VARARGS|METH_KEYWORDS, Cxt_is_fs_mounted_HELP}, + {"is_lazy", (PyCFunction)Cxt_is_lazy, METH_NOARGS, Cxt_is_lazy_HELP}, + {"is_nomtab", (PyCFunction)Cxt_is_nomtab, METH_NOARGS, Cxt_is_nomtab_HELP}, + {"is_rdonly_umount", (PyCFunction)Cxt_is_rdonly_umount, METH_NOARGS, Cxt_is_rdonly_umount_HELP}, + {"is_restricted", (PyCFunction)Cxt_is_restricted, METH_NOARGS, Cxt_is_restricted_HELP}, + {"is_sloppy", (PyCFunction)Cxt_is_sloppy, METH_NOARGS, Cxt_is_sloppy_HELP}, + {"is_verbose", (PyCFunction)Cxt_is_verbose, METH_NOARGS, Cxt_is_verbose_HELP}, + {"is_child", (PyCFunction)Cxt_is_child, METH_NOARGS, Cxt_is_child_HELP}, + {"is_parent", (PyCFunction)Cxt_is_parent, METH_NOARGS, Cxt_is_parent_HELP}, + {"is_loopdel", (PyCFunction)Cxt_is_loopdel, METH_NOARGS, Cxt_is_loopdel_HELP}, + {"is_nocanonicalize", (PyCFunction)Cxt_is_nocanonicalize, METH_NOARGS, Cxt_is_nocanonicalize_HELP}, + {"is_nohelpers", (PyCFunction)Cxt_is_nohelpers, METH_NOARGS, Cxt_is_nohelpers_HELP}, + {"is_swapmatch", (PyCFunction)Cxt_is_swapmatch, METH_NOARGS, Cxt_is_swapmatch_HELP}, + {"mount", (PyCFunction)Cxt_mount, METH_NOARGS, Cxt_mount_HELP}, + {"prepare_mount", (PyCFunction)Cxt_prepare_mount, METH_NOARGS, Cxt_prepare_mount_HELP}, + {"prepare_umount", (PyCFunction)Cxt_prepare_umount, METH_NOARGS, Cxt_prepare_umount_HELP}, + {"umount", (PyCFunction)Cxt_umount, METH_NOARGS, Cxt_umount_HELP}, + {"syscall_called", (PyCFunction)Cxt_syscall_called, METH_NOARGS, Cxt_syscall_called_HELP}, + {"disable_swapmatch", (PyCFunction)Cxt_disable_swapmatch, METH_VARARGS|METH_KEYWORDS, Cxt_disable_swapmatch_HELP}, + {"tab_applied", (PyCFunction)Cxt_tab_applied, METH_NOARGS, Cxt_tab_applied_HELP}, + {NULL} +}; + +static PyObject *Context_repr(CxtObject *self) +{ + return PyString_FromFormat("", + self, + self->cxt->mtab_path ? self->cxt->mtab_path : "None", + self->cxt->utab_path ? self->cxt->utab_path : "None", + self->cxt->restricted ? "True" : "False"); +} + +PyTypeObject CxtType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "libmount.Cxt", /*tp_name*/ + sizeof(CxtObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Cxt_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Context_repr, + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Cxt_HELP, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Cxt_methods, /* tp_methods */ + Cxt_members, /* tp_members */ + Cxt_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Cxt_init, /* tp_init */ + 0, /* tp_alloc */ + Cxt_new, /* tp_new */ +}; + +void pymnt_init_context(PyObject *mod) +{ + if (PyType_Ready(&CxtType) < 0) + return; + + Py_INCREF(&CxtType); + PyModule_AddObject(mod, "Cxt", (PyObject *)&CxtType); +} + + diff --git a/libmount/python/fs.c b/libmount/python/fs.c new file mode 100644 index 000000000..d82cf866d --- /dev/null +++ b/libmount/python/fs.c @@ -0,0 +1,790 @@ +/* + * 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. + */ + +/* + * TODO: + * mnt_fs_match_{source,target} + * mnt_fs_get_{attribute,option} + */ + +#include "pylibmount.h" + +#define Fs_HELP "Fs(bindsrc=None, source=None, root=None, target=None, fstype=None, options=None, attributes=None, freq=0, passno=0)" + +static PyMemberDef Fs_members[] = { + {NULL} +}; + +static PyObject *Fs_get_tag(FsObject *self) +{ + const char *tag = NULL, *val = NULL; + PyObject *result; + + mnt_fs_get_tag(self->fs, &tag, &val); + + result = Py_BuildValue("(ss)", tag, val); + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; +} +/* id */ +static PyObject *Fs_get_id(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_id(self->fs)); +} +/* parent_id */ +static PyObject *Fs_get_parent_id(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_parent_id(self->fs)); +} +/* devno */ +static PyObject *Fs_get_devno(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_devno(self->fs)); +} +#define Fs_print_debug_HELP "print_debug(ostream)\n\n" +static PyObject *Fs_print_debug(FsObject *self, PyObject *args, PyObject *kwds) +{ + PyFileObject *stream = NULL; + int rc; + FILE *f = NULL; + char *kwlist[] = {"ostream", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &PyFile_Type, &stream)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + f = PyFile_AsFile((PyObject *)stream); + return (rc = mnt_fs_print_debug(self->fs, f)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +/* + ** Fs getters/setters + */ + +/* bindsrc */ +static PyObject *Fs_get_bindsrc(FsObject *self, void *closure __attribute__((unused))) +{ + return PyObjectResultStr(mnt_fs_get_bindsrc(self->fs)); +} + +static int Fs_set_bindsrc(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *bindsrc = NULL; + int rc = 0; + + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(bindsrc = pystos(value))) + return -1; + + rc = mnt_fs_set_bindsrc(self->fs, bindsrc); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* comment */ +static PyObject *Fs_get_comment(FsObject *self, void *closure __attribute__((unused))) +{ + return PyObjectResultStr(mnt_fs_get_comment(self->fs)); +} + +static int Fs_set_comment(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *comment = NULL; + int rc = 0; + + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(comment = pystos(value))) + return -1; + + rc = mnt_fs_set_comment(self->fs, comment); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* source */ +static PyObject *Fs_get_source(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_source(self->fs)); +} + +static int Fs_set_source(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *source = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(source = pystos(value))) + return -1; + + rc = mnt_fs_set_source(self->fs, source); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* srcpath */ +static PyObject *Fs_get_srcpath(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_srcpath(self->fs)); +} +/* root */ +static PyObject *Fs_get_root(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_root(self->fs)); +} + +static int Fs_set_root(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *root = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(root = pystos(value))) + return -1; + + rc = mnt_fs_set_root(self->fs, root); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* target */ +static PyObject *Fs_get_target(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_target(self->fs)); +} + +static int Fs_set_target(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *target = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(target = pystos(value))) + return -1; + + rc = mnt_fs_set_target(self->fs, target); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* fstype */ +static PyObject *Fs_get_fstype(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_fstype(self->fs)); +} + +static int Fs_set_fstype(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *fstype = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(fstype = pystos(value))) + return -1; + + rc = mnt_fs_set_fstype(self->fs, fstype); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* optstr */ +static PyObject *Fs_get_options(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_options(self->fs)); +} + +static int Fs_set_options(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *options = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(options = pystos(value))) + return -1; + + rc = mnt_fs_set_options(self->fs, options); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* vfs_optstr */ +static PyObject *Fs_get_vfs_options(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_vfs_options(self->fs)); +} + +/* opt_fields */ +static PyObject *Fs_get_optional_fields(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_optional_fields(self->fs)); +} + +/* fs_optstr */ +static PyObject *Fs_get_fs_options(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_fs_options(self->fs)); +} + +/* user_optstr */ +static PyObject *Fs_get_user_options(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_user_options(self->fs)); +} + +/* attrs */ +static PyObject *Fs_get_attributes(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_attributes(self->fs)); +} + +static int Fs_set_attributes(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *attributes = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(attributes = pystos(value))) + return -1; + + rc = mnt_fs_set_attributes(self->fs, attributes); + if (rc) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +/* freq */ +static PyObject *Fs_get_freq(FsObject *self, void *closure __attribute__((unused))) +{ + return PyObjectResultInt(mnt_fs_get_freq(self->fs)); +} + +static int Fs_set_freq(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + int freq = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + + freq = PyInt_AsLong(value); + if (freq == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "type conversion failed"); + return -1; + } + return mnt_fs_set_freq(self->fs, freq); +} +/* passno */ +static PyObject *Fs_get_passno(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_passno(self->fs)); +} + +static int Fs_set_passno(FsObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + int passno = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + else if (!PyInt_Check(value)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return -1; + } + + passno = PyInt_AsLong(value); + if (passno == -1 && PyErr_Occurred()) { + PyErr_SetString(PyExc_RuntimeError, "type conversion failed"); + return -1; + } + return mnt_fs_set_passno(self->fs, passno); +} +/* swaptype */ + +static PyObject *Fs_get_swaptype(FsObject *self) +{ + return PyObjectResultStr(mnt_fs_get_swaptype(self->fs)); +} + +/* size */ + +static PyObject *Fs_get_size(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_size(self->fs)); +} + +/* usedsize */ + +static PyObject *Fs_get_usedsize(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_usedsize(self->fs)); +} +/* priority */ + +static PyObject *Fs_get_priority(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_priority(self->fs)); +} +/* propagation */ +#define Fs_get_propagation_HELP "get_propagation(flags)\n\n\ +Note that this function set flags to zero if not found any propagation flag\n\ +in mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored\n\ +in the mountinfo file.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Fs_get_propagation(FsObject *self, PyObject *args, PyObject *kwds) +{ + unsigned long flags; + char *kwlist[] = {"flags", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "k", kwlist, &flags)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultInt(mnt_fs_get_propagation(self->fs, &flags)); +} +/* tid */ + +static PyObject *Fs_get_tid(FsObject *self) +{ + return PyObjectResultInt(mnt_fs_get_tid(self->fs)); +} +#define Fs_is_kernel_HELP "is_kernel()\n\nReturns 1 if the filesystem description is read from kernel e.g. /proc/mounts." +static PyObject *Fs_is_kernel(FsObject *self) +{ + return PyBool_FromLong(mnt_fs_is_kernel(self->fs)); +} +#define Fs_is_netfs_HELP "is_netfs()\n\nReturns 1 if the filesystem is a network filesystem" +static PyObject *Fs_is_netfs(FsObject *self) +{ + return PyBool_FromLong(mnt_fs_is_netfs(self->fs)); +} +#define Fs_is_pseudofs_HELP "is_pseudofs()\n\nReturns 1 if the filesystem is a pseudo fs type (proc, cgroups)" +static PyObject *Fs_is_pseudofs(FsObject *self) +{ + return PyBool_FromLong(mnt_fs_is_pseudofs(self->fs)); +} +#define Fs_is_swaparea_HELP "is_swaparea()\n\nReturns 1 if the filesystem uses \"swap\" as a type" +static PyObject *Fs_is_swaparea(FsObject *self) +{ + return PyBool_FromLong(mnt_fs_is_swaparea(self->fs)); +} +#define Fs_append_attributes_HELP "append_attributes(optstr)\n\n\ +Appends mount attributes." +static PyObject *Fs_append_attributes(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"optstr", NULL}; + char *optstr = NULL; + int rc; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_fs_append_attributes(self->fs, optstr)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +#define Fs_append_options_HELP "append_options(optstr)\n\n\ +Parses (splits) optstr and appends results to VFS, FS and userspace lists \ +of options." +static PyObject *Fs_append_options(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"optstr", NULL}; + char *optstr = NULL; + int rc; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_fs_append_options(self->fs, optstr)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +#define Fs_prepend_attributes_HELP "prepend_attributes(optstr)\n\n\ +Prepends mount attributes." +static PyObject *Fs_prepend_attributes(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"optstr", NULL}; + char *optstr = NULL; + int rc; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_fs_prepend_attributes(self->fs, optstr)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +#define Fs_prepend_options_HELP "prepend_options(optstr)\n\n\ +Parses (splits) optstr and prepends results to VFS, FS and userspace lists \ +of options." +static PyObject *Fs_prepend_options(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"optstr", NULL}; + char *optstr = NULL; + int rc; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_fs_prepend_options(self->fs, optstr)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +#define Fs_match_fstype_HELP "match_fstype(pattern)\n\n\ +pattern: filesystem name or comma delimited list(string) of names\n\n\ +The pattern list of filesystem can be prefixed with a global\n\ +\"no\" prefix to invert matching of the whole list. The \"no\" could\n\ +also be used for individual items in the pattern list. So,\n\ +\"nofoo,bar\" has the same meaning as \"nofoo,nobar\".\n\ +\"bar\" : \"nofoo,bar\" -> False (global \"no\" prefix)\n\ +\"bar\" : \"foo,bar\" -> True\n\ +\"bar\" : \"foo,nobar\" -> False\n\n\ +Returns True if type is matching, else False." /* TODO: Test this */ +static PyObject *Fs_match_fstype(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"pattern", NULL}; + char *pattern = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &pattern)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_fs_match_fstype(self->fs, pattern)); +} +#define Fs_match_options_HELP "match_options(options)\n\n\ +options: comma delimited list of options (and nooptions)\n\ +Returns True if fs type is matching to options else False." +static PyObject *Fs_match_options(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"options", NULL}; + char *options = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &options)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_fs_match_options(self->fs, options)); +} +#define Fs_streq_srcpath_HELP "streq_srcpath(srcpath)\n\n\ +Compares fs source path with path. The tailing slash is ignored.\n\ +Returns True if fs source path equal to path, otherwise False." +static PyObject *Fs_streq_srcpath(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"srcpath", NULL}; + char *srcpath = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &srcpath)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_fs_streq_srcpath(self->fs, srcpath)); +} +#define Fs_streq_target_HELP "streq_target(target)\n\n\ +Compares fs target path with path. The tailing slash is ignored.\n\ +See also Fs.match_target().\n\ +Returns True if fs target path equal to path, otherwise False." +static PyObject *Fs_streq_target(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"target", NULL}; + char *target = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &target)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_fs_streq_target(self->fs, target)); +} + +#define Fs_copy_fs_HELP "copy_fs(dest=None)\n\n\ +If dest is None, a new object is created, if any fs \ +field is already set, then the field is NOT overwritten." +static PyObject *Fs_copy_fs(FsObject *self, PyObject *args, PyObject *kwds); +static PyMethodDef Fs_methods[] = { + {"get_propagation", (PyCFunction)Fs_get_propagation, METH_VARARGS|METH_KEYWORDS, Fs_get_propagation_HELP}, + {"mnt_fs_append_attributes", (PyCFunction)Fs_append_attributes, METH_VARARGS|METH_KEYWORDS, Fs_append_attributes_HELP}, + {"append_options", (PyCFunction)Fs_append_options, METH_VARARGS|METH_KEYWORDS, Fs_append_options_HELP}, + {"mnt_fs_prepend_attributes", (PyCFunction)Fs_prepend_attributes, METH_VARARGS|METH_KEYWORDS, Fs_prepend_attributes_HELP}, + {"prepend_options", (PyCFunction)Fs_prepend_options, METH_VARARGS|METH_KEYWORDS, Fs_prepend_options_HELP}, + {"copy_fs", (PyCFunction)Fs_copy_fs, METH_VARARGS|METH_KEYWORDS, Fs_copy_fs_HELP}, + {"is_kernel", (PyCFunction)Fs_is_kernel, METH_NOARGS, Fs_is_kernel_HELP}, + {"is_netfs", (PyCFunction)Fs_is_netfs, METH_NOARGS, Fs_is_netfs_HELP}, + {"is_pseudofs", (PyCFunction)Fs_is_pseudofs, METH_NOARGS, Fs_is_pseudofs_HELP}, + {"is_swaparea", (PyCFunction)Fs_is_swaparea, METH_NOARGS, Fs_is_swaparea_HELP}, + {"match_fstype", (PyCFunction)Fs_match_fstype, METH_VARARGS|METH_KEYWORDS, Fs_match_fstype_HELP}, + {"match_options", (PyCFunction)Fs_match_options, METH_VARARGS|METH_KEYWORDS, Fs_match_options_HELP}, + {"streq_srcpath", (PyCFunction)Fs_streq_srcpath, METH_VARARGS|METH_KEYWORDS, Fs_streq_srcpath_HELP}, + {"streq_target", (PyCFunction)Fs_streq_target, METH_VARARGS|METH_KEYWORDS, Fs_streq_target_HELP}, + {"print_debug", (PyCFunction)Fs_print_debug, METH_VARARGS|METH_KEYWORDS, Fs_print_debug_HELP}, + {NULL} +}; + +static void Fs_dealloc(FsObject *self) +{ + mnt_free_fs(self->fs); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject *Fs_new(PyTypeObject *type, PyObject *args __attribute__((unused)), + PyObject *kwds __attribute__((unused))) +{ + FsObject *self = (FsObject*)type->tp_alloc(type, 0); + if (self) + self->fs = NULL; + + return (PyObject *)self; +} + +static int Fs_init(FsObject *self, PyObject *args, PyObject *kwds) +{ + char *bindsrc = NULL, *source = NULL, *root = NULL, *target = NULL; + char *fstype = NULL, *options = NULL, *attributes =NULL; + int freq = 0; int passno = 0; + int rc = 0; + char *kwlist[] = {"bindsrc", "source", "root", "target", + "fstype", "options", "attributes", "freq", "passno", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sssssssii", kwlist, + &bindsrc, &source, &root, &target, &fstype, &options, + &attributes, &freq, &passno)) { + PyErr_SetString(PyExc_TypeError, "Invalid type"); + return -1; + } + if (self->fs) + mnt_free_fs(self->fs); + + self->fs = mnt_new_fs(); + if (bindsrc) { + if ((rc = mnt_fs_set_bindsrc(self->fs, bindsrc))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (source) { + if ((rc = mnt_fs_set_source(self->fs, source))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (root) { + if ((rc = mnt_fs_set_root(self->fs, root))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (target) { + if ((rc = mnt_fs_set_target(self->fs, target))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (fstype) { + if ((rc = mnt_fs_set_fstype(self->fs, fstype))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (options) { + if ((rc = mnt_fs_set_options(self->fs, options))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + if (attributes) { + if ((rc = mnt_fs_set_attributes(self->fs, attributes))) { + PyErr_SetString(PyExc_MemoryError, MEMORY_ERR); + return rc; + } + } + mnt_fs_set_freq(self->fs, freq); + mnt_fs_set_passno(self->fs, passno); + self->fs->userdata = (void *)self; /* store a pointer to self, convenient when resetting the table */ + return 0; +} + +/* + * missing: + * attribute + * option + */ +static PyGetSetDef Fs_getseters[] = { + {"id", (getter)Fs_get_id, NULL, "mountinfo[1]: ID", NULL}, + {"parent", (getter)Fs_get_parent_id, NULL, "mountinfo[2]: parent", NULL}, + {"devno", (getter)Fs_get_devno, NULL, "mountinfo[3]: st_dev", NULL}, + {"bindsrc", (getter)Fs_get_bindsrc, (setter)Fs_set_bindsrc, "utab, full path from fstab[1] for bind mounts", NULL}, + {"comment", (getter)Fs_get_comment, (setter)Fs_set_comment, "fstab entry comment", NULL}, + {"source", (getter)Fs_get_source, (setter)Fs_set_source, "fstab[1], mountinfo[10], swaps[1]: source dev, file, dir or TAG", NULL}, + {"srcpath", (getter)Fs_get_srcpath, NULL, "mount source path or NULL in case of error or when the path is not defined.", NULL}, + {"root", (getter)Fs_get_root, (setter)Fs_set_root, "mountinfo[4]: root of the mount within the FS", NULL}, + {"target", (getter)Fs_get_target, (setter)Fs_set_target, "mountinfo[5], fstab[2]: mountpoint", NULL}, + {"fstype", (getter)Fs_get_fstype, (setter)Fs_set_fstype, "mountinfo[9], fstab[3]: filesystem type", NULL}, + {"options", (getter)Fs_get_options, (setter)Fs_set_options, "fstab[4]: merged options", NULL}, + {"vfs_options", (getter)Fs_get_vfs_options, NULL, "mountinfo[6]: fs-independent (VFS) options", NULL}, + {"opt_fields", (getter)Fs_get_optional_fields, NULL, "mountinfo[7]: optional fields", NULL}, + {"fs_options", (getter)Fs_get_fs_options, NULL, "mountinfo[11]: fs-dependent options", NULL}, + {"usr_options", (getter)Fs_get_user_options, NULL, "userspace mount options", NULL}, + {"attributes", (getter)Fs_get_attributes, (setter)Fs_set_attributes, "mount attributes", NULL}, + {"freq", (getter)Fs_get_freq, (setter)Fs_set_freq, "fstab[5]: dump frequency in days", NULL}, + {"passno", (getter)Fs_get_passno, (setter)Fs_set_passno, "fstab[6]: pass number on parallel fsck", NULL}, + {"swaptype", (getter)Fs_get_swaptype, NULL, "swaps[2]: device type", NULL}, + {"size", (getter)Fs_get_size, NULL, "saps[3]: swaparea size", NULL}, + {"usedsize", (getter)Fs_get_usedsize, NULL, "swaps[4]: used size", NULL}, + {"priority", (getter)Fs_get_priority, NULL, "swaps[5]: swap priority", NULL}, + {"tag", (getter)Fs_get_tag, NULL, "(Name, Value)", NULL}, + {"tid", (getter)Fs_get_tid, NULL, "/proc//mountinfo, otherwise zero", NULL}, + {NULL} +}; + +static PyObject *Fs_repr(FsObject *self) +{ + return PyString_FromFormat( + "", + self, + self->fs->source ? self->fs->source : "None", + self->fs->target ? self->fs->target : "None", + self->fs->fstype ? self->fs->fstype : "None"); +} + +PyObject *PyObjectResultFs(struct libmnt_fs *fs) +{ + if (!fs) { + PyErr_SetString(LibmountError, "internal exception"); + return NULL; + } + if (fs->userdata) { + Py_INCREF(fs->userdata); + return (PyObject *)fs->userdata; + } + + FsObject *result = PyObject_New(FsObject, &FsType); + if (!result) { + UL_RaiseExc(ENOMEM); + return NULL; + } + /* Creating an encapsualing object: increment the refcount, so that code + * such as: + * tab.next_fs() + * doesn't call the destructor, which would free our fs struct as well + */ + Py_INCREF(result); + result->fs = fs; + result->fs->userdata = (void *)result; + return (PyObject *)result; +} + +static PyObject *Fs_copy_fs(FsObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *dest = NULL; + char *kwlist[] = {"dest", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &dest)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + if (PyObject_TypeCheck(dest, &FsType)) { /* existing object passed as argument */ + if (!mnt_copy_fs(((FsObject *)dest)->fs, self->fs)) + return NULL; + else + return (PyObject *)dest; + } + else if (dest == Py_None) { /* create new object */ + FsObject *result = PyObject_New(FsObject, &FsType); + result->fs = mnt_copy_fs(NULL, self->fs); + result->fs->userdata = (void *)result; /* keep a pointer to encapsulating object */ + return (PyObject *)result; + } + else { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } +} + + +PyTypeObject FsType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "libmount.Fs", /*tp_name*/ + sizeof(FsObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Fs_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc)Fs_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Fs_HELP, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Fs_methods, /* tp_methods */ + Fs_members, /* tp_members */ + Fs_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Fs_init, /* tp_init */ + 0, /* tp_alloc */ + Fs_new, /* tp_new */ +}; + +void pymnt_init_fs(PyObject *mod) +{ + if (PyType_Ready(&FsType) < 0) + return; + + Py_INCREF(&FsType); + PyModule_AddObject(mod, "Fs", (PyObject *)&FsType); +} + diff --git a/libmount/python/pylibmount.c b/libmount/python/pylibmount.c new file mode 100644 index 000000000..2303a22c1 --- /dev/null +++ b/libmount/python/pylibmount.c @@ -0,0 +1,205 @@ +/* + * 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; + +PyObject *UL_IncRef(void *killme) +{ + Py_INCREF(killme); + return killme; +} + +/* 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) +{ + 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; + PyObject *result = Py_BuildValue("s", s); + if (!result) + PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR); + return result; +} + +/* wrapper around a common use case for PyString_AsString() */ +char *pystos(PyObject *pys) +{ + if (!PyString_Check(pys)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyString_AsString(pys); +} + +/* + * 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. Contex.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." + +static PyMethodDef libmount_methods[] = { + {NULL} /* Sentinel */ +}; + +#ifndef PyMODINIT_FUNC +# define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC initpylibmount(void); +PyMODINIT_FUNC initpylibmount(void) +{ + PyObject *m = Py_InitModule3("pylibmount", libmount_methods, PYLIBMOUNT_DESC); + + if (!m) + return; + + LibmountError = PyErr_NewException("libmount.Error", NULL, NULL); + Py_INCREF(LibmountError); + PyModule_AddObject(m, "Error", (PyObject *)LibmountError); + + pymnt_init_fs(m); + pymnt_init_table(m); + pymnt_init_context(m); + + /* + * 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); +} + diff --git a/libmount/python/pylibmount.h b/libmount/python/pylibmount.h new file mode 100644 index 000000000..6903d1f7f --- /dev/null +++ b/libmount/python/pylibmount.h @@ -0,0 +1,78 @@ +#ifndef UTIL_LINUX_PYLIBMOUNT_H +#define UTIL_LINUX_PYLIBMOUNT_H + +#include +#include + +#include "libmount.h" +#include "mountP.h" + +#define NODEL_ATTR "This attribute cannot be deleted" +#define CONSTRUCT_ERR "Error during object construction" +#define ARG_ERR "Invalid number or type of arguments" +#define NOFS_ERR "No filesystems to mount" +#define MEMORY_ERR strerror(ENOMEM) +#define CONV_ERR "Type conversion failed" + +/* + * fs.c + */ +typedef struct { + PyObject_HEAD + struct libmnt_fs *fs; +} FsObject; + +extern PyTypeObject FsType; + +extern PyObject *PyObjectResultFs(struct libmnt_fs *fs); + +extern void pymnt_init_fs(PyObject *mod); + +/* + * tab.c + */ +typedef struct { + PyObject_HEAD + + struct libmnt_table *tab; + struct libmnt_iter *iter; + PyObject *errcb; +} TabObject; + +extern PyTypeObject TabType; + +extern PyObject *PyObjectResultTab(struct libmnt_table *tab); + +extern void pymnt_init_table(PyObject *mod); +extern void pymnt_free_table(struct libmnt_table *tab); +extern int pymnt_table_parser_errcb(struct libmnt_table *tb, const char *filename, int line); + +/* + * context.c + */ +typedef struct { + PyObject_HEAD + + struct libmnt_context *cxt; + PyObject *table_errcb; + +} CxtObject; + +extern PyTypeObject CxtType; +extern void pymnt_init_context(PyObject *mod); + +/* + * misc + */ +extern PyObject *LibmountError; +extern PyObject *UL_IncRef(void *killme); +extern void *UL_RaiseExc(int e); + +extern PyObject *PyObjectResultInt(int i); +extern PyObject *PyObjectResultStr(const char *s); + +extern char *pystos(PyObject *pys); + + + +#endif /* UTIL_LINUX_PYLIBMOUNT */ diff --git a/libmount/python/tab.c b/libmount/python/tab.c new file mode 100644 index 000000000..636866af6 --- /dev/null +++ b/libmount/python/tab.c @@ -0,0 +1,725 @@ +/* + * 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" + +static PyMemberDef Tab_members[] = { + {NULL} +}; + +static int Tab_set_parser_errcb(TabObject *self, PyObject *func, void *closure __attribute__((unused))) +{ + if (!func) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!PyCallable_Check(func)) + return -1; + else { + PyObject *tmp = self->errcb; + Py_INCREF(func); + self->errcb = func; + Py_XDECREF(tmp); + } + return 0; +} + +static PyObject *Tab_get_intro_comment(TabObject *self, void *closure __attribute__((unused))) +{ + return PyObjectResultStr(mnt_table_get_intro_comment(self->tab)); +} + +static int Tab_set_intro_comment(TabObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *comment = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(comment = pystos(value))) + return -1; + + if ((rc = mnt_table_set_intro_comment(self->tab, comment))) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} + +static PyObject *Tab_get_trailing_comment(TabObject *self, void *closure __attribute__((unused))) +{ + return PyObjectResultStr(mnt_table_get_trailing_comment(self->tab)); +} + +static int Tab_set_trailing_comment(TabObject *self, PyObject *value, void *closure __attribute__((unused))) +{ + char *comment = NULL; + int rc = 0; + if (!value) { + PyErr_SetString(PyExc_TypeError, NODEL_ATTR); + return -1; + } + if (!(comment = pystos(value))) + return -1; + + if ((rc = mnt_table_set_trailing_comment(self->tab, comment))) { + UL_RaiseExc(-rc); + return -1; + } + return 0; +} +#define Tab_enable_comments_HELP "enable_comments(enable)\n\n\ +Enables parsing of comments.\n\n\ +The initial (intro) file comment is accessible by\n\ +Tab.intro_comment. The intro and the comment of the first fstab\ +entry has to be separated by blank line. The filesystem comments are\n\ +accessible by Fs.comment. The tailing fstab comment is accessible\n\ +by Tab.trailing_comment.\n\ +\n\ +\n\ +\n\ +#\n\ +# Intro comment\n\ +#\n\ +\n\ +# this comments belongs to the first fs\n\ +LABEL=foo /mnt/foo auto defaults 1 2\n\ +# this comments belongs to the second fs\n\ +LABEL=bar /mnt/bar auto defaults 1 2 \n\ +# tailing comment\n\ +\n\ +" +static PyObject *Tab_enable_comments(TabObject *self, PyObject *args, PyObject *kwds) +{ + int enable = 0; + char *kwlist[] = {"enable", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &enable)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + mnt_table_enable_comments(self->tab, enable); + Py_INCREF(self); + return (PyObject *)self; +} + +#define Tab_replace_file_HELP "replace_file(filename)\n\n\ +This function replaces filename with the new content from TabObject." +static PyObject *Tab_replace_file(TabObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + char *filename = NULL; + char *kwlist[] = {"filename", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &filename)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_replace_file(self->tab, filename)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_write_file_HELP "write_file(file)\n\n\ +This function writes tab to file(stream)" +static PyObject *Tab_write_file(TabObject *self, PyObject *args, PyObject *kwds) +{ + int rc; + PyFileObject *stream = NULL; + FILE *f = NULL; + char *kwlist[] = {"file", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &PyFile_Type, &stream)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + f = PyFile_AsFile((PyObject *)stream); + return (rc = mnt_table_write_file(self->tab, f)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_find_devno_HELP "find_devno(devno, [direction])\n\n\ +Note that zero could be valid device number for root pseudo filesystem (e.g.\ +tmpfs\n\ +Returns a tab entry or None" +static PyObject *Tab_find_devno(TabObject *self, PyObject *args, PyObject *kwds) +{ + dev_t devno; + int direction = MNT_ITER_BACKWARD; + char *kwlist[] = {"devno", "direction", NULL}; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "I|i", kwlist, &devno, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_devno(self->tab, devno, direction)); +} + +#define Tab_find_mountpoint_HELP "find_mountpoint(path, [direction])\n\n\ +Returns a tab entry or None." +static PyObject *Tab_find_mountpoint(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *path; + int direction = MNT_ITER_BACKWARD; + char *kwlist[] = {"path", "direction", NULL}; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &path, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_mountpoint(self->tab, path, direction)); +} + +#define Tab_find_pair_HELP "find_pair(source, target, [direction])\n\n\ +Returns a tab entry or None." +static PyObject *Tab_find_pair(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"source", "target", "direction", NULL}; + char *source; + char *target; + int direction = MNT_ITER_BACKWARD; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|i", kwlist, &source, &target, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_pair(self->tab, source, target, direction)); +} + +#define Tab_find_source_HELP "find_source(source, [direction])\n\n\ +Returns a tab entry or None." +static PyObject *Tab_find_source(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"source", "direction", NULL}; + char *source; + int direction = MNT_ITER_BACKWARD; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &source, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_source(self->tab, source, direction)); +} + +#define Tab_find_target_HELP "find_target(target, [direction])\n\n\ +Try to lookup an entry in given tab, possible are three iterations, first\n\ +with path, second with realpath(path) and third with realpath(path)\n\ +against realpath(fs->target). The 2nd and 3rd iterations are not performed\n\ +when tb cache is not set (cache not implemented yet).n\ +\n\ +Returns a tab entry or None." +static PyObject *Tab_find_target(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"target", "direction", NULL}; + char *target; + int direction = MNT_ITER_BACKWARD; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &target, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_target(self->tab, target, direction)); +} + +#define Tab_find_srcpath_HELP "find_srcpath(srcpath, [direction])\n\n\ +Try to lookup an entry in given tab, possible are four iterations, first\n\ +with path, second with realpath(path), third with tags (LABEL, UUID, ..)\n\ +from path and fourth with realpath(path) against realpath(entry->srcpath).\n\ +\n\ +The 2nd, 3rd and 4th iterations are not performed when tb cache is not\n\ +set (not implemented yet).\n\ +\n\ +Note that None is a valid source path; it will be replaced with \"none\". The\n\ +\"none\" is used in /proc/{mounts,self/mountinfo} for pseudo filesystems.\n\ +\n\ +Returns a tab entry or None." +static PyObject *Tab_find_srcpath(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"srcpath", "direction", NULL}; + char *srcpath; + int direction = MNT_ITER_BACKWARD; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwlist, &srcpath, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_srcpath(self->tab, srcpath, direction)); +} + +#define Tab_find_tag_HELP "find_tag(tag, val, [direction])\n\n\ +Try to lookup an entry in given tab, first attempt is lookup by tag and\n\ +val, for the second attempt the tag is evaluated (converted to the device\n\ +name) and Tab.find_srcpath() is preformed. The second attempt is not\n\ +performed when tb cache is not set (not implemented yet).\n\ +\n\ +Returns a tab entry or NULL." +static PyObject *Tab_find_tag(TabObject *self, PyObject *args, PyObject *kwds) +{ + char *kwlist[] = {"tag", "val", "direction", NULL}; + char *tag; + char *val; + int direction = MNT_ITER_BACKWARD; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss|i", kwlist, &tag, &val, &direction)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyObjectResultFs(mnt_table_find_tag(self->tab, tag, val, direction)); +} + +static PyObject *Tab_get_nents(TabObject *self) +{ + return PyObjectResultInt(mnt_table_get_nents(self->tab)); +} + +#define Tab_is_fs_mounted_HELP "is_fs_mounted(fstab_fs)\n\n\ +Checks if the fstab_fs entry is already in the tb table. The \"swap\" is\n\ +ignored. This function explicitly compares source, target and root of the\n\ +filesystems.\n\ +\n\ +Note that source and target are canonicalized only if a cache for tb is\n\ +defined (not implemented yet). The target canonicalization may\n\ +trigger automount on autofs mountpoints!\n\ +\n\ +Don't use it if you want to know if a device is mounted, just use\n\ +Tab.find_source() for the device.\n\ +\n\ +This function is designed mostly for \"mount -a\".\n\ +\n\ +Returns a boolean value." +static PyObject *Tab_is_fs_mounted(TabObject *self, PyObject *args, PyObject *kwds) +{ + FsObject *fs; + char *kwlist[] = {"fstab_fs", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &FsType, &fs)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return PyBool_FromLong(mnt_table_is_fs_mounted(self->tab, fs->fs)); +} + +#define Tab_parse_file_HELP "parse_file(file)\n\n\ +Parses whole table (e.g. /etc/mtab) and appends new records to the tab.\n\ +\n\ +The libmount parser ignores broken (syntax error) lines, these lines are\n\ +reported to caller by errcb() function (see Tab.parser_errcb).\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_parse_file(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + char *file = NULL; + char *kwlist[] = {"file", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &file)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_parse_file(self->tab, file)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_parse_fstab_HELP "parse_fstab([fstab])\n\n\ +This function parses /etc/fstab and appends new lines to the tab. If the\n\ +filename is a directory then Tab.parse_dir() is called.\n\ +\n\ +See also Tab.parser_errcb.\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_parse_fstab(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + char *fstab = NULL; + char *kwlist[] = {"fstab", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &fstab)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_parse_fstab(self->tab, fstab)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_parse_mtab_HELP "parse_mtab([mtab])\n\n\ +This function parses /etc/mtab or /proc/self/mountinfo\n\ +/run/mount/utabs or /proc/mounts.\n\ +\n\ +See also Tab.parser_errcb().\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_parse_mtab(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + char *mtab = NULL; + char *kwlist[] = {"mtab", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &mtab)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_parse_mtab(self->tab, mtab)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_parse_dir_HELP "parse_dir(dir)\n\n\ +The directory:\n\ +- files are sorted by strverscmp(3)\n\ +- files that start with \".\" are ignored (e.g. \".10foo.fstab\")\n\ +- files without the \".fstab\" extension are ignored\n\ +\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_parse_dir(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + char *dir = NULL; + char *kwlist[] = {"dir", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &dir)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_parse_dir(self->tab, dir)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_parse_swaps_HELP "parse_swaps(swaps)\n\n\ +This function parses /proc/swaps and appends new lines to the tab" +static PyObject *Tab_parse_swaps(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + char *swaps = NULL; + char *kwlist[] = {"swaps", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &swaps)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + return (rc = mnt_table_parse_swaps(self->tab, swaps)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_parse_stream_HELP "parse_stream(stream, filename)\n\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_parse_stream(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + PyFileObject *stream = NULL; + char *filename = NULL; + FILE *f; + char *kwlist[] = {"stream", "filename", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!s", kwlist, &PyFile_Type, &stream, &filename)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + f = PyFile_AsFile((PyObject *)stream); + return (rc = mnt_table_parse_stream(self->tab, f, filename)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} +#define Tab_add_fs_HELP "add_fs(fs)\n\nAdds a new entry to tab.\n\ +Returns self or raises an exception in case of an error." + +static PyObject *Tab_add_fs(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + FsObject *fs = NULL; + char *kwlist[] = {"fs", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &FsType, &fs)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + Py_INCREF(fs); + return (rc = mnt_table_add_fs(self->tab, fs->fs)) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_remove_fs_HELP "remove_fs(fs)\n\n\ +Returns self or raises an exception in case of an error." +static PyObject *Tab_remove_fs(TabObject *self, PyObject* args, PyObject *kwds) +{ + int rc; + FsObject *fs = NULL; + char *kwlist[] = {"fs", NULL}; + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist, &FsType, &fs)) { + PyErr_SetString(PyExc_TypeError, ARG_ERR); + return NULL; + } + rc = mnt_table_remove_fs(self->tab, fs->fs); + Py_DECREF(fs); + return (rc) ? UL_RaiseExc(-rc) : UL_IncRef(self); +} + +#define Tab_next_fs_HELP "next_fs()\n\n\ +Returns the next Fs on success, raises an exception in case of an error and None at end of list.\n\ +\n\ +Example:\n\ +\n\ +\n\ +import libmount\n\ +import functools\n\ +for fs in iter(functools.partial(tb.next_fs), None): {\n\ + dir = Fs.target\n\ + print \"mount point: {:s}\n\".format(dir)\n\ +}\n\ +\n\ +\n\ +\n\ +lists all mountpoints from fstab in backward order." +static PyObject *Tab_next_fs(TabObject *self) +{ + struct libmnt_fs *fs; + int rc; + + /* Reset the builtin iterator after reaching the end of the list */ + rc = mnt_table_next_fs(self->tab, self->iter, &fs); + if (rc == 1) { + mnt_reset_iter(self->iter, MNT_ITER_FORWARD); + Py_RETURN_NONE; + } else if (rc) + return UL_RaiseExc(-rc); + + return PyObjectResultFs(fs); +} + +static PyMethodDef Tab_methods[] = { + {"enable_comments", (PyCFunction)Tab_enable_comments, METH_VARARGS|METH_KEYWORDS, Tab_enable_comments_HELP}, + {"find_pair", (PyCFunction)Tab_find_pair, METH_VARARGS|METH_KEYWORDS, Tab_find_pair_HELP}, + {"find_source", (PyCFunction)Tab_find_source, METH_VARARGS|METH_KEYWORDS, Tab_find_source_HELP}, + {"find_srcpath", (PyCFunction)Tab_find_srcpath, METH_VARARGS|METH_KEYWORDS, Tab_find_srcpath_HELP}, + {"find_tag", (PyCFunction)Tab_find_tag, METH_VARARGS|METH_KEYWORDS, Tab_find_tag_HELP}, + {"find_target", (PyCFunction)Tab_find_target, METH_VARARGS|METH_KEYWORDS, Tab_find_target_HELP}, + {"find_devno", (PyCFunction)Tab_find_devno, METH_VARARGS|METH_KEYWORDS, Tab_find_devno_HELP}, + {"find_mountpoint", (PyCFunction)Tab_find_mountpoint, METH_VARARGS|METH_KEYWORDS, Tab_find_mountpoint_HELP}, + {"parse_file", (PyCFunction)Tab_parse_file, METH_VARARGS|METH_KEYWORDS, Tab_parse_file_HELP}, + {"parse_fstab", (PyCFunction)Tab_parse_fstab, METH_VARARGS|METH_KEYWORDS, Tab_parse_fstab_HELP}, + {"parse_mtab", (PyCFunction)Tab_parse_mtab, METH_VARARGS|METH_KEYWORDS, Tab_parse_mtab_HELP}, + {"parse_dir", (PyCFunction)Tab_parse_dir, METH_VARARGS|METH_KEYWORDS, Tab_parse_dir_HELP}, + {"parse_swaps", (PyCFunction)Tab_parse_swaps, METH_VARARGS|METH_KEYWORDS, Tab_parse_swaps_HELP}, + {"is_fs_mounted", (PyCFunction)Tab_is_fs_mounted, METH_VARARGS|METH_KEYWORDS, Tab_is_fs_mounted_HELP}, + {"parse_stream", (PyCFunction)Tab_parse_stream, METH_VARARGS|METH_KEYWORDS, Tab_parse_stream_HELP}, + {"add_fs", (PyCFunction)Tab_add_fs, METH_VARARGS|METH_KEYWORDS, Tab_add_fs_HELP}, + {"remove_fs", (PyCFunction)Tab_remove_fs, METH_VARARGS|METH_KEYWORDS, Tab_remove_fs_HELP}, + {"next_fs", (PyCFunction)Tab_next_fs, METH_NOARGS, Tab_next_fs_HELP}, + {"write_file", (PyCFunction)Tab_write_file, METH_VARARGS|METH_KEYWORDS, Tab_write_file_HELP}, + {"replace_file", (PyCFunction)Tab_replace_file, METH_VARARGS|METH_KEYWORDS, Tab_replace_file_HELP}, + {NULL} +}; + +/* mnt_free_tab() with a few necessary additions */ +void pymnt_free_table(struct libmnt_table *tab) +{ + if (!tab) + return; + + while (!list_empty(&tab->ents)) { + struct libmnt_fs *fs = list_entry(tab->ents.next, struct libmnt_fs, ents); + + if (fs->userdata) + Py_DECREF(fs->userdata); /* (possible) destruction via object destructor */ + else + mnt_free_fs(fs); /* no encapsulating object, free fs */ + } + + mnt_free_table(tab); +} + +static void Tab_destructor(TabObject *self) +{ + pymnt_free_table(self->tab); + mnt_free_iter(self->iter); + Py_XDECREF(self->errcb); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject *Tab_new(PyTypeObject *type, PyObject *args __attribute__((unused)), + PyObject *kwds __attribute__((unused))) +{ + TabObject *self = (TabObject*)type->tp_alloc(type, 0); + if (self) { + self->tab = NULL; + self->iter = NULL; + self->errcb = NULL; + } + + return (PyObject *)self; +} +/* explicit tab.__init__() serves as mnt_reset_table(tab) would in C + * and as mnt_new_table{,_from_dir,_from_file}() with proper arguments */ +#define Tab_HELP "Tab(path=None, errcb=None)" +static int Tab_init(TabObject *self, PyObject *args, PyObject *kwds) +{ + struct libmnt_cache *cache; + char *path = NULL; + char *kwlist[] = {"path", "errcb", NULL}; + PyObject *errcb = NULL; + struct stat buf; + memset (&buf, 0, sizeof(struct stat)); + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sO", kwlist, &path, &errcb)) { + return -1; + } + + pymnt_free_table(self->tab); + self->tab = NULL; + + if (self->iter) + mnt_reset_iter(self->iter, MNT_ITER_FORWARD); + else + self->iter = mnt_new_iter(MNT_ITER_FORWARD); + if (errcb) { + if (!PyCallable_Check(errcb)) { + return -1; + } + PyObject *tmp = self->errcb; + Py_INCREF(errcb); + self->errcb = errcb; + Py_XDECREF(tmp); + } else { + Py_XDECREF(self->errcb); + self->errcb = NULL; + } + + if (path) { + if (stat(path, &buf)) { + /* TODO: weird */ + PyErr_SetFromErrno(PyExc_RuntimeError); + return -1; + } + if (S_ISREG(buf.st_mode)) + self->tab = mnt_new_table_from_file(path); + else if (S_ISDIR(buf.st_mode)) + self->tab = mnt_new_table_from_dir(path); + } else + self->tab = mnt_new_table(); + + /* Always set custom handler when using libmount from python */ + self->tab->errcb = pymnt_table_parser_errcb; + self->tab->userdata = (void *)self; + + /* TODO: perhaps make this optional? */ + cache = mnt_new_cache(); + if (!cache) + return -1; + + mnt_table_set_cache(self->tab, cache); + + return 0; +} + +/* Handler for the tab->errcb callback */ +int pymnt_table_parser_errcb(struct libmnt_table *tb, const char *filename, int line) +{ + int rc = 0; + PyObject *arglist, *result; + + if (tb->userdata && ((TabObject*)(tb->userdata))->errcb) { + arglist = Py_BuildValue("(Osi)", tb->userdata, filename, line); + if (!arglist) + return -ENOMEM; + + /* A python callback was set, so tb is definitely encapsulated in an object */ + result = PyEval_CallObject(((TabObject *)(tb->userdata))->errcb, arglist); + Py_DECREF(arglist); + + if (!result) + return -EINVAL; + + if (!PyArg_Parse(result, "i", &rc)) + rc = -EINVAL; + + Py_DECREF(result); + } + return rc; +} + +PyObject *PyObjectResultTab(struct libmnt_table *tab) +{ + if (!tab) { + PyErr_SetString(LibmountError, "internal exception"); + return NULL; + } + if (tab->userdata) { + Py_INCREF(tab->userdata); + return (PyObject *)tab->userdata; + } + + TabObject *result = PyObject_New(TabObject, &TabType); + if (!result) { + UL_RaiseExc(ENOMEM); + return NULL; + } + /* Creating an encapsualing object: increment the refcount, so that code + * such as: + * cxt.get_fstab() + * doesn't call the destructor, which would free our tab struct as well + */ + Py_INCREF(result); + result->tab = tab; + result->iter = mnt_new_iter(MNT_ITER_FORWARD); + result->tab->userdata = (void *)result; + result->errcb = NULL; + return (PyObject *)result; +} + +static PyGetSetDef Tab_getseters[] = { + {"nents", (getter)Tab_get_nents, NULL, "number of valid entries in tab", NULL}, + {"intro_comment", (getter)Tab_get_intro_comment, (setter)Tab_set_intro_comment, "fstab intro comment", NULL}, + {"trailing_comment", (getter)Tab_get_trailing_comment, (setter)Tab_set_trailing_comment, "fstab trailing comment", NULL}, + {"errcb", NULL, (setter)Tab_set_parser_errcb, "parser error callback", NULL}, + {NULL} +}; + + +static PyObject *Table_repr(TabObject *self) +{ + return PyString_FromFormat( + "", + self, + self->tab->nents, + self->tab->comms ? "True" : "False", + self->errcb ? pystos(PyObject_Repr(self->errcb)) : "None"); +} + +PyTypeObject TabType = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "libmount.Tab", /*tp_name*/ + sizeof(TabObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + (destructor)Tab_destructor, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) Table_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash */ + 0, /*tp_call*/ + 0, /*tp_str*/ + 0, /*tp_getattro*/ + 0, /*tp_setattro*/ + 0, /*tp_as_buffer*/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/ + Tab_HELP, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Tab_methods, /* tp_methods */ + Tab_members, /* tp_members */ + Tab_getseters, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Tab_init, /* tp_init */ + 0, /* tp_alloc */ + Tab_new, /* tp_new */ +}; + +void pymnt_init_table(PyObject *mod) +{ + if (PyType_Ready(&TabType) < 0) + return; + + Py_INCREF(&TabType); + PyModule_AddObject(mod, "Tab", (PyObject *)&TabType); +} + -- cgit v1.2.3-55-g7522