]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
pylibmount: basic code
authorOndrej Oprala <ooprala@redhat.com>
Mon, 19 Aug 2013 13:00:15 +0000 (15:00 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 19 Aug 2013 13:00:15 +0000 (15:00 +0200)
[kzak@redhat.com: - split to more patches
                  - split to more .c files]

Signed-off-by: Ondrej Oprala <ooprala@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
libmount/python/Makemodule.am
libmount/python/context.c [new file with mode: 0644]
libmount/python/fs.c [new file with mode: 0644]
libmount/python/pylibmount.c [new file with mode: 0644]
libmount/python/pylibmount.h [new file with mode: 0644]
libmount/python/tab.c [new file with mode: 0644]

index 30946d635bbd074684330c52ee855048245eda4f..bafa8ada8bb99040e3a2657b8f222d02c8e23e08 100644 (file)
@@ -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 (file)
index 0000000..5df84ac
--- /dev/null
@@ -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("<libmount.Context object at %p, mtab_path=%s, utab_path=%s, restricted=%s>",
+                       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 (file)
index 0000000..d82cf86
--- /dev/null
@@ -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/<tid>/mountinfo, otherwise zero", NULL},
+       {NULL}
+};
+
+static PyObject *Fs_repr(FsObject *self)
+{
+       return PyString_FromFormat(
+                       "<libmount.Fs object at %p, source=%s, target=%s, fstype=%s>",
+                       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 (file)
index 0000000..2303a22
--- /dev/null
@@ -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 (file)
index 0000000..6903d1f
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef UTIL_LINUX_PYLIBMOUNT_H
+#define UTIL_LINUX_PYLIBMOUNT_H
+
+#include <Python.h>
+#include <structmember.h>
+
+#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 (file)
index 0000000..636866a
--- /dev/null
@@ -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\
+<informalexample>\n\
+<programlisting>\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\
+</programlisting>\n\
+</informalexample>"
+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\
+<informalexample>\n\
+<programlisting>\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\
+</programlisting>\n\
+</informalexample>\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(
+                       "<libmount.Table object at %p, entries=%d, comments_enabled=%s, errcb=%s>",
+                       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);
+}
+