summaryrefslogtreecommitdiff
path: root/libmount
diff options
context:
space:
mode:
Diffstat (limited to 'libmount')
-rw-r--r--libmount/COPYING4
-rw-r--r--libmount/Makemodule.am2
-rw-r--r--libmount/docs/libmount-sections.txt28
-rw-r--r--libmount/python/Makemodule.am33
-rw-r--r--libmount/python/__init__.py2
-rw-r--r--libmount/python/context.c1228
-rw-r--r--libmount/python/fs.c850
-rw-r--r--libmount/python/pylibmount.c301
-rw-r--r--libmount/python/pylibmount.h126
-rw-r--r--libmount/python/tab.c781
-rwxr-xr-xlibmount/python/test_mount_context.py173
-rwxr-xr-xlibmount/python/test_mount_tab.py164
-rwxr-xr-xlibmount/python/test_mount_tab_update.py59
-rw-r--r--libmount/src/Makemodule.am7
-rw-r--r--libmount/src/cache.c89
-rw-r--r--libmount/src/context.c266
-rw-r--r--libmount/src/context_loopdev.c39
-rw-r--r--libmount/src/context_mount.c130
-rw-r--r--libmount/src/context_umount.c61
-rw-r--r--libmount/src/fs.c222
-rw-r--r--libmount/src/init.c14
-rw-r--r--libmount/src/iter.c10
-rw-r--r--libmount/src/libmount.h.in42
-rw-r--r--libmount/src/libmount.sym35
-rw-r--r--libmount/src/lock.c36
-rw-r--r--libmount/src/mountP.h34
-rw-r--r--libmount/src/optmap.c9
-rw-r--r--libmount/src/optstr.c112
-rw-r--r--libmount/src/tab.c538
-rw-r--r--libmount/src/tab_diff.c25
-rw-r--r--libmount/src/tab_parse.c160
-rw-r--r--libmount/src/tab_update.c178
-rw-r--r--libmount/src/utils.c146
-rw-r--r--libmount/src/version.c6
34 files changed, 5312 insertions, 598 deletions
diff --git a/libmount/COPYING b/libmount/COPYING
index 41fe6fd62..be1a5b3a1 100644
--- a/libmount/COPYING
+++ b/libmount/COPYING
@@ -4,5 +4,5 @@ License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later
version.
-The complete text of the license is available at the
-Documentation/licenses/COPYING.LGPLv2.1 file.
+The complete text of the license is available in the
+../Documentation/licenses/COPYING.LGPLv2.1 file.
diff --git a/libmount/Makemodule.am b/libmount/Makemodule.am
index 81d550a47..8546c2f9b 100644
--- a/libmount/Makemodule.am
+++ b/libmount/Makemodule.am
@@ -1,6 +1,7 @@
if BUILD_LIBMOUNT
include libmount/src/Makemodule.am
+include libmount/python/Makemodule.am
if ENABLE_GTK_DOC
# Docs uses separate Makefiles
@@ -11,5 +12,4 @@ pkgconfig_DATA += libmount/mount.pc
PATHFILES += libmount/mount.pc
EXTRA_DIST += libmount/COPYING
-
endif # BUILD_LIBMOUNT
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 2c3dab722..6affbfbb6 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -3,6 +3,8 @@
libmnt_cache
mnt_new_cache
mnt_free_cache
+mnt_ref_cache
+mnt_unref_cache
mnt_cache_device_has_tag
mnt_cache_find_tag_value
mnt_cache_read_tags
@@ -36,11 +38,14 @@ mnt_context_enable_verbose
mnt_context_get_cache
mnt_context_get_fs
mnt_context_get_fstab
+mnt_context_get_fstab_userdata
mnt_context_get_fstype
+mnt_context_get_fs_userdata
mnt_context_get_helper_status
mnt_context_get_lock
mnt_context_get_mflags
mnt_context_get_mtab
+mnt_context_get_mtab_userdata
mnt_context_get_options
mnt_context_get_optsmode
mnt_context_get_source
@@ -167,11 +172,15 @@ libmnt_fs
mnt_copy_fs
mnt_free_fs
mnt_free_mntent
+mnt_ref_fs
+mnt_unref_fs
mnt_fs_append_attributes
+mnt_fs_append_comment
mnt_fs_append_options
mnt_fs_get_attribute
mnt_fs_get_attributes
mnt_fs_get_bindsrc
+mnt_fs_get_comment
mnt_fs_get_devno
mnt_fs_get_freq
mnt_fs_get_fs_options
@@ -209,6 +218,7 @@ mnt_fs_prepend_options
mnt_fs_print_debug
mnt_fs_set_attributes
mnt_fs_set_bindsrc
+mnt_fs_set_comment
mnt_fs_set_freq
mnt_fs_set_fstype
mnt_fs_set_options
@@ -279,9 +289,14 @@ libmnt_table
mnt_free_table
mnt_new_table
mnt_reset_table
+mnt_ref_table
+mnt_unref_table
mnt_new_table_from_dir
mnt_new_table_from_file
mnt_table_add_fs
+mnt_table_append_intro_comment
+mnt_table_append_trailing_comment
+mnt_table_enable_comments
mnt_table_find_devno
mnt_table_find_mountpoint
mnt_table_find_next_fs
@@ -290,10 +305,16 @@ mnt_table_find_source
mnt_table_find_srcpath
mnt_table_find_tag
mnt_table_find_target
+mnt_table_first_fs
mnt_table_get_cache
+mnt_table_get_intro_comment
mnt_table_get_nents
mnt_table_get_root_fs
+mnt_table_get_trailing_comment
+mnt_table_get_userdata
+mnt_table_is_empty
mnt_table_is_fs_mounted
+mnt_table_last_fs
mnt_table_next_child_fs
mnt_table_next_fs
mnt_table_parse_dir
@@ -304,8 +325,12 @@ mnt_table_parse_stream
mnt_table_parse_swaps
mnt_table_remove_fs
mnt_table_set_cache
+mnt_table_set_intro_comment
mnt_table_set_iter
mnt_table_set_parser_errcb
+mnt_table_set_trailing_comment
+mnt_table_set_userdata
+mnt_table_with_comments
</SECTION>
<SECTION>
@@ -322,6 +347,8 @@ mnt_diff_tables
libmnt_update
mnt_free_update
mnt_new_update
+mnt_table_replace_file
+mnt_table_write_file
mnt_update_force_rdonly
mnt_update_get_filename
mnt_update_get_fs
@@ -343,6 +370,7 @@ mnt_has_regular_mtab
mnt_mangle
mnt_match_fstype
mnt_match_options
+mnt_tag_is_valid
mnt_unmangle
</SECTION>
diff --git a/libmount/python/Makemodule.am b/libmount/python/Makemodule.am
new file mode 100644
index 000000000..efe210efd
--- /dev/null
+++ b/libmount/python/Makemodule.am
@@ -0,0 +1,33 @@
+EXTRA_DIST += libmount/python/__init__.py
+
+if BUILD_PYLIBMOUNT
+
+pylibmountexecdir = $(pyexecdir)/libmount
+
+# Please, don't use $pythondir for the scripts. We have to use the same
+# directory for binary stuff as well as for the scripts otherwise it's
+# not possible to install 32-bit and 64-bit version on the same system.
+pylibmountexec_LTLIBRARIES = pylibmount.la
+pylibmountexec_SCRIPTS = libmount/python/__init__.py
+
+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 $(PYTHON_LIBS)
+
+pylibmount_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(PYTHON_CFLAGS) \
+ -I$(ul_libmount_incdir) \
+ -fno-strict-aliasing #-ggdb3 -O0
+
+pylibmount_la_LDFLAGS = \
+ -avoid-version -module -shared -export-dynamic
+
+CLEANFILES += *.img
+
+endif # BUILD_PYLIBMOUNT
diff --git a/libmount/python/__init__.py b/libmount/python/__init__.py
new file mode 100644
index 000000000..09104e2e2
--- /dev/null
+++ b/libmount/python/__init__.py
@@ -0,0 +1,2 @@
+from .pylibmount import *
+
diff --git a/libmount/python/context.c b/libmount/python/context.c
new file mode 100644
index 000000000..408c8bd75
--- /dev/null
+++ b/libmount/python/context.c
@@ -0,0 +1,1228 @@
+/*
+ * 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 Context_members[] = {
+ { NULL }
+};
+
+static PyObject *Context_set_tables_errcb(ContextObjext *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 Context_dealloc(ContextObjext *self)
+{
+ if (!self->cxt) /* if init fails */
+ return;
+
+ Py_XDECREF(mnt_context_get_fs_userdata(self->cxt));
+ Py_XDECREF(mnt_context_get_fstab_userdata(self->cxt));
+ Py_XDECREF(mnt_context_get_mtab_userdata(self->cxt));
+
+ mnt_free_context(self->cxt);
+ PyFree(self);
+}
+
+static PyObject *Context_new(PyTypeObject *type,
+ PyObject *args __attribute__((unused)),
+ PyObject *kwds __attribute__((unused)))
+{
+ ContextObjext *self = (ContextObjext*) 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 Context_HELP "Context(source=None, target=None, fstype=None, " \
+ "options=None, mflags=0, fstype_pattern=None, " \
+ "options_pattern=None, fs=None, fstab=None, optsmode=0)"
+static int Context_init(ContextObjext *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;
+ TableObject *fstab = NULL;
+ int rc = 0;
+ char *kwlist[] = {
+ "source", "target", "fstype",
+ "options", "mflags", "fstype_pattern",
+ "options_pattern", "fs", "fstab",
+ "optsmode"
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(
+ args, kwds, "|sssskssO!O!i", kwlist,
+ &source, &target, &fstype, &options, &mflags,
+ &fstype_pattern, &options_pattern, &FsType, &fs,
+ &TableType, &fstab, &optsmode, &syscall_status)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+
+ if (self->cxt)
+ mnt_free_context(self->cxt);
+
+ self->cxt = mnt_new_context();
+ if (!self->cxt) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return -1;
+ }
+
+ if (source && (rc = mnt_context_set_source(self->cxt, source))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (target && (rc = mnt_context_set_target(self->cxt, target))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (fstype && (rc = mnt_context_set_fstype(self->cxt, fstype))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (options && (rc = mnt_context_set_options(self->cxt, options))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (fstype_pattern && (rc = mnt_context_set_fstype_pattern(self->cxt, fstype_pattern))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (options_pattern && (rc = mnt_context_set_options_pattern(self->cxt, options_pattern))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (fs && (rc = mnt_context_set_fs(self->cxt, fs->fs))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (fstab && (rc = mnt_context_set_fstab(self->cxt, fstab->tab))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ if (optsmode && (rc = mnt_context_set_optsmode(self->cxt, optsmode))) {
+ UL_RaiseExc(-rc);
+ return -1;
+ }
+
+ mnt_context_set_mflags(self->cxt, mflags);
+ mnt_context_set_optsmode(self->cxt, optsmode);
+ mnt_context_set_tables_errcb(self->cxt, pymnt_table_parser_errcb);
+
+ return 0;
+}
+
+#define Context_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 *Context_enable_fake(ContextObjext *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;
+ }
+ rc = mnt_context_enable_fake(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_force(ContextObjext *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;
+ }
+ rc = mnt_context_enable_force(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_lazy(ContextObjext *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;
+ }
+ rc = mnt_context_enable_lazy(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_loopdel(ContextObjext *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;
+ }
+ rc = mnt_context_enable_loopdel(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_rdonly_umount(ContextObjext *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;
+ }
+ rc = mnt_context_enable_rdonly_umount(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_sloppy(ContextObjext *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;
+ }
+ rc = mnt_context_enable_sloppy(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_verbose(ContextObjext *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;
+ }
+ rc = mnt_context_enable_verbose(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_enable_fork(ContextObjext *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;
+ }
+ rc = mnt_context_enable_fork(self->cxt, enable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_disable_canonicalize(ContextObjext *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;
+ }
+ rc = mnt_context_disable_canonicalize(self->cxt, disable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_disable_helpers(ContextObjext *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;
+ }
+ rc = mnt_context_disable_helpers(self->cxt, disable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_disable_mtab(ContextObjext *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;
+ }
+ rc = mnt_context_disable_mtab(self->cxt, disable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_disable_swapmatch(ContextObjext *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;
+ }
+ rc = mnt_context_disable_swapmatch(self->cxt, disable);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+static int Context_set_source(ContextObjext *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 Context_set_mountdata(ContextObjext *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 Context_set_target(ContextObjext *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 Context_set_fstype(ContextObjext *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 Context_set_options(ContextObjext *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 Context_set_fstype_pattern(ContextObjext *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 Context_set_options_pattern(ContextObjext *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 Context_set_fs(ContextObjext *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);
+ Py_XDECREF(mnt_context_get_fs_userdata(self->cxt));
+
+ return mnt_context_set_fs(self->cxt, fs->fs);
+}
+
+static int Context_set_fstab(ContextObjext *self, PyObject *value, void *closure __attribute__((unused)))
+{
+ TableObject *fstab;
+
+ if (!value) {
+ PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
+ return -1;
+ }
+ if (!PyArg_Parse(value, "O!", &TableType, &fstab)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+ Py_INCREF(fstab);
+ Py_XDECREF(mnt_context_get_fstab_userdata(self->cxt));
+
+ return mnt_context_set_fstab(self->cxt, fstab->tab);
+}
+
+static int Context_set_optsmode(ContextObjext *self, PyObject *value, void *closure __attribute__((unused)))
+{
+ int optsmode;
+
+ if (!value) {
+ PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
+ return -1;
+ }
+ else if (!PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+ optsmode = PyLong_AsLong(value);
+ return mnt_context_set_optsmode(self->cxt, optsmode);
+}
+
+static int Context_set_syscall_status(ContextObjext *self, PyObject *value, void *closure __attribute__((unused)))
+{
+ int syscall_status;
+
+ if (!value) {
+ PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
+ return -1;
+ }
+ else if (!PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+ syscall_status = PyLong_AsLong(value);
+ return mnt_context_set_syscall_status(self->cxt, syscall_status);
+}
+
+static int Context_set_user_mflags(ContextObjext *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 Context_set_mflags(ContextObjext *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 *Context_get_mflags(ContextObjext *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 *Context_get_user_mflags(ContextObjext *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 Context_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 *Context_reset_status(ContextObjext *self)
+{
+ int rc = mnt_context_reset_status(self->cxt);
+
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_is_fake_HELP "is_fake()\n\n" \
+"Returns True if fake flag is enabled or False"
+static PyObject *Context_is_fake(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_fake(self->cxt));
+}
+
+#define Context_is_force_HELP "is_force()\n\n" \
+"Returns True if force umounting flag is enabled or False"
+static PyObject *Context_is_force(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_force(self->cxt));
+}
+
+#define Context_is_lazy_HELP "is_lazy()\n\n" \
+"Returns True if lazy umount is enabled or False"
+static PyObject *Context_is_lazy(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_lazy(self->cxt));
+}
+
+#define Context_is_nomtab_HELP "is_nomtab()\n\n" \
+ "Returns True if no-mtab is enabled or False"
+static PyObject *Context_is_nomtab(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_nomtab(self->cxt));
+}
+
+#define Context_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 *Context_is_rdonly_umount(ContextObjext *self)
+{
+ int rc = mnt_context_is_rdonly_umount(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_is_restricted_HELP "is_restricted()\n\n" \
+ "Returns False for unrestricted mount (user is root), or True for non-root mounts"
+static PyObject *Context_is_restricted(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_restricted(self->cxt));
+}
+
+#define Context_is_sloppy_HELP "is_sloppy()\n\n" \
+ "Returns True if sloppy flag is enabled or False"
+static PyObject *Context_is_sloppy(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_sloppy(self->cxt));
+}
+
+#define Context_is_verbose_HELP "is_verbose()\n\n" \
+ "Returns True if verbose flag is enabled or False"
+static PyObject *Context_is_verbose(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_verbose(self->cxt));
+}
+#define Context_is_fs_mounted_HELP "is_fs_mounted(fs, mounted)\n\n" \
+ "Returns self or raises an exception in case of an error."
+static PyObject *Context_is_fs_mounted(ContextObjext *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 Context_is_child_HELP "is_child()\n\n" \
+ "Returns True if mount -F enabled and the current context is child, or False"
+static PyObject *Context_is_child(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_child(self->cxt));
+}
+
+#define Context_is_fork_HELP "is_fork()\n\n" \
+ "Returns True if fork (mount -F) is enabled or False"
+static PyObject *Context_is_fork(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_fork(self->cxt));
+}
+
+#define Context_is_parent_HELP "is_parent()\n\n" \
+ "Returns True if mount -F enabled and the current context is parent, or False"
+static PyObject *Context_is_parent(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_parent(self->cxt));
+}
+
+#define Context_is_loopdel_HELP "is_loopdel()\n\n" \
+ "Returns True if loop device should be deleted after umount (umount -d) or False."
+static PyObject *Context_is_loopdel(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_loopdel(self->cxt));
+}
+
+#define Context_is_nocanonicalize_HELP "is_nocanonicalize()\n\n" \
+ "Returns True if no-canonicalize mode enabled or False."
+static PyObject *Context_is_nocanonicalize(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_nocanonicalize(self->cxt));
+}
+
+#define Context_is_nohelpers_HELP "is_nohelpers()\n\n" \
+ "Returns True if helpers are disabled (mount -i) or False."
+static PyObject *Context_is_nohelpers(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_nohelpers(self->cxt));
+}
+
+#define Context_syscall_called_HELP "syscall_called()\n\n" \
+ "Returns True if mount(2) syscall has been called, or False."
+static PyObject *Context_syscall_called(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_syscall_called(self->cxt));
+}
+
+#define Context_is_swapmatch_HELP "is_swapmatch()\n\n" \
+ "Returns True if swap between source and target is allowed (default is True) or False."
+static PyObject *Context_is_swapmatch(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_is_swapmatch(self->cxt));
+}
+
+#define Context_tab_applied_HELP "tab_applied()\n\n" \
+ "Returns True if fstab (or mtab) has been applied to the context, False otherwise."
+static PyObject *Context_tab_applied(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_tab_applied(self->cxt));
+}
+
+#define Context_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 *Context_apply_fstab(ContextObjext *self)
+{
+ int rc = mnt_context_apply_fstab(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_helper_executed_HELP "helper_executed()\n\n" \
+ "Returns True if mount.type helper has been executed, or False."
+static PyObject *Context_helper_executed(ContextObjext *self)
+{
+ return PyBool_FromLong(mnt_context_helper_executed(self->cxt));
+}
+
+static PyObject *Context_get_source(ContextObjext *self)
+{
+ return PyObjectResultStr(mnt_context_get_source(self->cxt));
+}
+
+static PyObject *Context_get_target(ContextObjext *self)
+{
+ return PyObjectResultStr(mnt_context_get_target(self->cxt));
+}
+
+static PyObject *Context_get_options(ContextObjext *self)
+{
+ return PyObjectResultStr(mnt_context_get_options(self->cxt));
+}
+
+static PyObject *Context_get_fstype(ContextObjext *self)
+{
+ return PyObjectResultStr(mnt_context_get_fstype(self->cxt));
+}
+
+static PyObject *Context_get_fs(ContextObjext *self)
+{
+ return PyObjectResultFs(mnt_context_get_fs(self->cxt));
+}
+
+static PyObject *Context_get_fstab(ContextObjext *self)
+{
+ struct libmnt_table *tab = NULL;
+
+ if (mnt_context_get_fstab(self->cxt, &tab) != 0 || !tab)
+ return NULL;
+ return PyObjectResultTab(tab);
+}
+
+static PyObject *Context_get_mtab(ContextObjext *self)
+{
+ struct libmnt_table *tab = NULL;
+
+ if (mnt_context_get_mtab(self->cxt, &tab) != 0 || !tab)
+ return NULL;
+ return PyObjectResultTab(tab);
+}
+
+static PyObject *Context_get_optsmode(ContextObjext *self)
+{
+ return PyObjectResultInt(mnt_context_get_optsmode(self->cxt));
+}
+
+static PyObject *Context_get_status(ContextObjext *self)
+{
+ return PyObjectResultInt(mnt_context_get_status(self->cxt));
+}
+
+static PyObject *Context_get_syscall_errno(ContextObjext *self)
+{
+ return PyObjectResultInt(mnt_context_get_syscall_errno(self->cxt));
+}
+
+#define Context_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 or an exception in case of other errors."
+static PyObject *Context_do_mount(ContextObjext *self)
+{
+ int rc = mnt_context_do_mount(self->cxt);
+ return rc ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self);
+}
+
+#define Context_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 or an exception in case of other errors."
+static PyObject *Context_do_umount(ContextObjext *self)
+{
+ int rc = mnt_context_do_umount(self->cxt);
+ return rc ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self);
+}
+
+#define Context_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 or an exception in case of other errors."
+static PyObject *Context_mount(ContextObjext *self)
+{
+ int rc = mnt_context_mount(self->cxt);
+ return rc ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self);
+}
+
+#define Context_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 or an exception in case of other errors."
+static PyObject *Context_umount(ContextObjext *self)
+{
+ int rc = mnt_context_umount(self->cxt);
+ return rc ? UL_RaiseExc(rc < 0 ? -rc : rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_finalize_mount(ContextObjext *self)
+{
+ int rc = mnt_context_finalize_mount(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_prepare_umount(ContextObjext *self)
+{
+ int rc = mnt_context_prepare_umount(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_prepare_mount(ContextObjext *self)
+{
+ int rc = mnt_context_prepare_mount(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_finalize_umount(ContextObjext *self)
+{
+ int rc = mnt_context_finalize_umount(self->cxt);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_find_umount_fs_HELP "find_umount_fs(tgt, pfs)\n\n" \
+ "Returns self or raises an exception in case of an error."
+static PyObject *Context_find_umount_fs(ContextObjext *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;
+ }
+
+ rc = mnt_context_find_umount_fs(self->cxt, tgt, &fs->fs);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_append_options_HELP "append_options(optstr)\n\n" \
+ "Returns self or raises an exception in case of an error."
+static PyObject *Context_append_options(ContextObjext *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;
+ }
+
+ rc = mnt_context_append_options(self->cxt, optstr);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_helper_setopt(ContextObjext *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;
+ }
+
+ rc = mnt_context_helper_setopt(self->cxt, c, arg);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Context_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 *Context_init_helper(ContextObjext *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;
+ }
+
+ rc = mnt_context_init_helper(self->cxt, action, flags);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+static PyGetSetDef Context_getseters[] = {
+ {"tables_errcb", NULL, (setter)Context_set_tables_errcb, "error callback function", NULL},
+ {"status", (getter)Context_get_status, NULL, "status", NULL},
+ {"source", (getter)Context_get_source, (setter)Context_set_source, "source", NULL},
+ {"target", (getter)Context_get_target, (setter)Context_set_target, "target", NULL},
+ {"fstype", (getter)Context_get_fstype, (setter)Context_set_fstype, "fstype", NULL},
+ {"options", (getter)Context_get_options, (setter)Context_set_options, "options", NULL},
+ {"mflags", (getter)Context_get_mflags, (setter)Context_set_mflags, "mflags", NULL},
+ {"mountdata", NULL, (setter)Context_set_mountdata, "mountdata", NULL},
+ {"fstype_pattern", NULL, (setter)Context_set_fstype_pattern, "fstype_pattern", NULL},
+ {"options_pattern", NULL, (setter)Context_set_options_pattern, "options_pattern", NULL},
+ {"fs", (getter)Context_get_fs, (setter)Context_set_fs, "filesystem description (type, mountpoint, device, ...)", NULL},
+ {"mtab", (getter)Context_get_mtab, NULL, "mtab entries", NULL},
+ {"fstab", (getter)Context_get_fstab, (setter)Context_set_fstab, "fstab (or mtab for some remounts)", NULL},
+ {"optsmode", (getter)Context_get_optsmode, (setter)Context_set_optsmode, "fstab optstr mode MNT_OPTSMODE_{AUTO,FORCE,IGNORE}", NULL},
+ {"syscall_errno", (getter)Context_get_syscall_errno, (setter)Context_set_syscall_status, "1: not_called yet, 0: success, <0: -errno", NULL},
+ {"user_mflags", (getter)Context_get_user_mflags, (setter)Context_set_user_mflags, "user mflags", NULL},
+ {NULL}
+};
+static PyMethodDef Context_methods[] = {
+ {"find_umount_fs", (PyCFunction)Context_find_umount_fs, METH_VARARGS|METH_KEYWORDS, Context_find_umount_fs_HELP},
+ {"reset_status", (PyCFunction)Context_reset_status, METH_NOARGS, Context_reset_status_HELP},
+ {"helper_executed", (PyCFunction)Context_helper_executed, METH_NOARGS, Context_helper_executed_HELP},
+ {"init_helper", (PyCFunction)Context_init_helper, METH_VARARGS|METH_KEYWORDS, Context_init_helper_HELP},
+ {"helper_setopt", (PyCFunction)Context_helper_setopt, METH_VARARGS|METH_KEYWORDS, Context_helper_setopt_HELP},
+ {"append_options", (PyCFunction)Context_append_options, METH_VARARGS|METH_KEYWORDS, Context_append_options_HELP},
+ {"apply_fstab", (PyCFunction)Context_apply_fstab, METH_NOARGS, Context_apply_fstab_HELP},
+ {"disable_canonicalize", (PyCFunction)Context_disable_canonicalize, METH_VARARGS|METH_KEYWORDS, Context_disable_canonicalize_HELP},
+ {"disable_helpers", (PyCFunction)Context_disable_helpers, METH_VARARGS|METH_KEYWORDS, Context_disable_helpers_HELP},
+ {"disable_mtab", (PyCFunction)Context_disable_mtab, METH_VARARGS|METH_KEYWORDS, Context_disable_mtab_HELP},
+ {"do_mount", (PyCFunction)Context_do_mount, METH_NOARGS, Context_do_mount_HELP},
+ {"do_umount", (PyCFunction)Context_do_umount, METH_NOARGS , Context_do_umount_HELP},
+ {"enable_fake", (PyCFunction)Context_enable_fake, METH_VARARGS|METH_KEYWORDS, Context_enable_fake_HELP},
+ {"enable_force", (PyCFunction)Context_enable_force, METH_VARARGS|METH_KEYWORDS, Context_enable_force_HELP},
+ {"enable_lazy", (PyCFunction)Context_enable_lazy, METH_VARARGS|METH_KEYWORDS, Context_enable_lazy_HELP},
+ {"enable_loopdel", (PyCFunction)Context_enable_loopdel, METH_VARARGS|METH_KEYWORDS, Context_enable_loopdel_HELP},
+ {"enable_rdonly_umount", (PyCFunction)Context_enable_rdonly_umount, METH_VARARGS|METH_KEYWORDS, Context_enable_rdonly_umount_HELP},
+ {"enable_sloppy", (PyCFunction)Context_enable_sloppy, METH_VARARGS|METH_KEYWORDS, Context_enable_sloppy_HELP},
+ {"enable_verbose", (PyCFunction)Context_enable_verbose, METH_VARARGS|METH_KEYWORDS, Context_enable_verbose_HELP},
+ {"enable_fork", (PyCFunction)Context_enable_fork, METH_VARARGS|METH_KEYWORDS, Context_enable_fork_HELP},
+ {"finalize_mount", (PyCFunction)Context_finalize_mount, METH_NOARGS, Context_finalize_mount_HELP},
+ {"finalize_umount", (PyCFunction)Context_finalize_umount, METH_NOARGS, Context_finalize_umount_HELP},
+ {"is_fake", (PyCFunction)Context_is_fake, METH_NOARGS, Context_is_fake_HELP},
+ {"is_force", (PyCFunction)Context_is_force, METH_NOARGS, Context_is_force_HELP},
+ {"is_fork", (PyCFunction)Context_is_fork, METH_NOARGS, Context_is_fork_HELP},
+ {"is_fs_mounted", (PyCFunction)Context_is_fs_mounted, METH_VARARGS|METH_KEYWORDS, Context_is_fs_mounted_HELP},
+ {"is_lazy", (PyCFunction)Context_is_lazy, METH_NOARGS, Context_is_lazy_HELP},
+ {"is_nomtab", (PyCFunction)Context_is_nomtab, METH_NOARGS, Context_is_nomtab_HELP},
+ {"is_rdonly_umount", (PyCFunction)Context_is_rdonly_umount, METH_NOARGS, Context_is_rdonly_umount_HELP},
+ {"is_restricted", (PyCFunction)Context_is_restricted, METH_NOARGS, Context_is_restricted_HELP},
+ {"is_sloppy", (PyCFunction)Context_is_sloppy, METH_NOARGS, Context_is_sloppy_HELP},
+ {"is_verbose", (PyCFunction)Context_is_verbose, METH_NOARGS, Context_is_verbose_HELP},
+ {"is_child", (PyCFunction)Context_is_child, METH_NOARGS, Context_is_child_HELP},
+ {"is_parent", (PyCFunction)Context_is_parent, METH_NOARGS, Context_is_parent_HELP},
+ {"is_loopdel", (PyCFunction)Context_is_loopdel, METH_NOARGS, Context_is_loopdel_HELP},
+ {"is_nocanonicalize", (PyCFunction)Context_is_nocanonicalize, METH_NOARGS, Context_is_nocanonicalize_HELP},
+ {"is_nohelpers", (PyCFunction)Context_is_nohelpers, METH_NOARGS, Context_is_nohelpers_HELP},
+ {"is_swapmatch", (PyCFunction)Context_is_swapmatch, METH_NOARGS, Context_is_swapmatch_HELP},
+ {"mount", (PyCFunction)Context_mount, METH_NOARGS, Context_mount_HELP},
+ {"prepare_mount", (PyCFunction)Context_prepare_mount, METH_NOARGS, Context_prepare_mount_HELP},
+ {"prepare_umount", (PyCFunction)Context_prepare_umount, METH_NOARGS, Context_prepare_umount_HELP},
+ {"umount", (PyCFunction)Context_umount, METH_NOARGS, Context_umount_HELP},
+ {"syscall_called", (PyCFunction)Context_syscall_called, METH_NOARGS, Context_syscall_called_HELP},
+ {"disable_swapmatch", (PyCFunction)Context_disable_swapmatch, METH_VARARGS|METH_KEYWORDS, Context_disable_swapmatch_HELP},
+ {"tab_applied", (PyCFunction)Context_tab_applied, METH_NOARGS, Context_tab_applied_HELP},
+ {NULL}
+};
+
+static PyObject *Context_repr(ContextObjext *self)
+{
+ return PyUnicode_FromFormat("<libmount.Context object at %p, restricted=%s>",
+ self, mnt_context_is_restricted(self->cxt) ? "True" : "False");
+}
+
+PyTypeObject ContextType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libmount.Context", /*tp_name*/
+ sizeof(ContextObjext), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Context_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*/
+ Context_HELP, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Context_methods, /* tp_methods */
+ Context_members, /* tp_members */
+ Context_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Context_init, /* tp_init */
+ 0, /* tp_alloc */
+ Context_new, /* tp_new */
+};
+
+void Context_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&ContextType) < 0)
+ return;
+
+ DBG(CXT, pymnt_debug("add to module"));
+
+ Py_INCREF(&ContextType);
+ PyModule_AddObject(mod, "Context", (PyObject *)&ContextType);
+}
+
+
diff --git a/libmount/python/fs.c b/libmount/python/fs.c
new file mode 100644
index 000000000..0789d3797
--- /dev/null
+++ b/libmount/python/fs.c
@@ -0,0 +1,850 @@
+/*
+ * 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"
+#include <errno.h>
+
+#define Fs_HELP "Fs(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;
+
+ if (mnt_fs_get_tag(self->fs, &tag, &val) != 0)
+ return NULL;
+
+ result = Py_BuildValue("(ss)", tag, val);
+ if (!result)
+ PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
+ return result;
+}
+
+static PyObject *Fs_get_id(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_id(self->fs));
+}
+
+static PyObject *Fs_get_parent_id(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_parent_id(self->fs));
+}
+
+static PyObject *Fs_get_devno(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_devno(self->fs));
+}
+
+#define Fs_print_debug_HELP "print_debug()\n\n"
+static PyObject *Fs_print_debug(FsObject *self)
+{
+ PySys_WriteStdout("------ fs: %p\n", self->fs);
+ PySys_WriteStdout("source: %s\n", mnt_fs_get_source(self->fs));
+ PySys_WriteStdout("target: %s\n", mnt_fs_get_target(self->fs));
+ PySys_WriteStdout("fstype: %s\n", mnt_fs_get_fstype(self->fs));
+
+ if (mnt_fs_get_options(self->fs))
+ PySys_WriteStdout("optstr: %s\n", mnt_fs_get_options(self->fs));
+ if (mnt_fs_get_vfs_options(self->fs))
+ PySys_WriteStdout("VFS-optstr: %s\n", mnt_fs_get_vfs_options(self->fs));
+ if (mnt_fs_get_fs_options(self->fs))
+ PySys_WriteStdout("FS-opstr: %s\n", mnt_fs_get_fs_options(self->fs));
+ if (mnt_fs_get_user_options(self->fs))
+ PySys_WriteStdout("user-optstr: %s\n", mnt_fs_get_user_options(self->fs));
+ if (mnt_fs_get_optional_fields(self->fs))
+ PySys_WriteStdout("optional-fields: '%s'\n", mnt_fs_get_optional_fields(self->fs));
+ if (mnt_fs_get_attributes(self->fs))
+ PySys_WriteStdout("attributes: %s\n", mnt_fs_get_attributes(self->fs));
+
+ if (mnt_fs_get_root(self->fs))
+ PySys_WriteStdout("root: %s\n", mnt_fs_get_root(self->fs));
+
+ if (mnt_fs_get_swaptype(self->fs))
+ PySys_WriteStdout("swaptype: %s\n", mnt_fs_get_swaptype(self->fs));
+ if (mnt_fs_get_size(self->fs))
+ PySys_WriteStdout("size: %jd\n", mnt_fs_get_size(self->fs));
+ if (mnt_fs_get_usedsize(self->fs))
+ PySys_WriteStdout("usedsize: %jd\n", mnt_fs_get_usedsize(self->fs));
+ if (mnt_fs_get_priority(self->fs))
+ PySys_WriteStdout("priority: %d\n", mnt_fs_get_priority(self->fs));
+
+ if (mnt_fs_get_bindsrc(self->fs))
+ PySys_WriteStdout("bindsrc: %s\n", mnt_fs_get_bindsrc(self->fs));
+ if (mnt_fs_get_freq(self->fs))
+ PySys_WriteStdout("freq: %d\n", mnt_fs_get_freq(self->fs));
+ if (mnt_fs_get_passno(self->fs))
+ PySys_WriteStdout("pass: %d\n", mnt_fs_get_passno(self->fs));
+ if (mnt_fs_get_id(self->fs))
+ PySys_WriteStdout("id: %d\n", mnt_fs_get_id(self->fs));
+ if (mnt_fs_get_parent_id(self->fs))
+ PySys_WriteStdout("parent: %d\n", mnt_fs_get_parent_id(self->fs));
+ if (mnt_fs_get_devno(self->fs))
+ PySys_WriteStdout("devno: %d:%d\n", major(mnt_fs_get_devno(self->fs)),
+ minor(mnt_fs_get_devno(self->fs)));
+ if (mnt_fs_get_tid(self->fs))
+ PySys_WriteStdout("tid: %d\n", mnt_fs_get_tid(self->fs));
+ if (mnt_fs_get_comment(self->fs))
+ PySys_WriteStdout("comment: '%s'\n", mnt_fs_get_comment(self->fs));
+ return UL_IncRef(self);
+}
+/*
+ ** Fs getters/setters
+ */
+
+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;
+}
+
+static PyObject *Fs_get_srcpath(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_srcpath(self->fs));
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+static PyObject *Fs_get_vfs_options(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_vfs_options(self->fs));
+}
+
+
+static PyObject *Fs_get_optional_fields(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_optional_fields(self->fs));
+}
+
+
+static PyObject *Fs_get_fs_options(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_fs_options(self->fs));
+}
+
+
+static PyObject *Fs_get_user_options(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_user_options(self->fs));
+}
+
+
+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;
+}
+
+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 (!PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+
+ freq = PyLong_AsLong(value);
+ if (freq == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, "type conversion failed");
+ return -1;
+ }
+ return mnt_fs_set_freq(self->fs, freq);
+}
+
+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 (!PyLong_Check(value)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return -1;
+ }
+
+ passno = PyLong_AsLong(value);
+ if (passno == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_RuntimeError, "type conversion failed");
+ return -1;
+ }
+ return mnt_fs_set_passno(self->fs, passno);
+}
+
+static PyObject *Fs_get_swaptype(FsObject *self)
+{
+ return PyObjectResultStr(mnt_fs_get_swaptype(self->fs));
+}
+
+static PyObject *Fs_get_size(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_size(self->fs));
+}
+
+static PyObject *Fs_get_usedsize(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_usedsize(self->fs));
+}
+
+static PyObject *Fs_get_priority(FsObject *self)
+{
+ return PyObjectResultInt(mnt_fs_get_priority(self->fs));
+}
+
+#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));
+}
+
+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;
+ }
+ rc = mnt_fs_append_attributes(self->fs, optstr);
+ return rc ? 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;
+ }
+ rc = mnt_fs_append_options(self->fs, optstr);
+ return rc ? 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;
+ }
+ rc = mnt_fs_prepend_attributes(self->fs, optstr);
+ return rc ? 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;
+ }
+ rc = mnt_fs_prepend_options(self->fs, optstr);
+ return rc ? 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."
+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_NOARGS, Fs_print_debug_HELP},
+ {NULL}
+};
+
+static void Fs_destructor(FsObject *self)
+{
+ DBG(FS, pymnt_debug_h(self->fs, "destrutor py-obj: %p, py-refcnt=%d",
+ self, (int) ((PyObject *) self)->ob_refcnt));
+ mnt_unref_fs(self->fs);
+ PyFree(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;
+ DBG(FS, pymnt_debug_h(self, "new"));
+ }
+ return (PyObject *) self;
+}
+
+static int Fs_init(FsObject *self, PyObject *args, PyObject *kwds)
+{
+ char *source = NULL, *root = NULL, *target = NULL;
+ char *fstype = NULL, *options = NULL, *attributes =NULL;
+ int freq = 0; int passno = 0;
+ int rc = 0;
+ char *kwlist[] = {
+ "source", "root", "target",
+ "fstype", "options", "attributes",
+ "freq", "passno", NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssii", kwlist,
+ &source, &root, &target, &fstype, &options,
+ &attributes, &freq, &passno)) {
+ PyErr_SetString(PyExc_TypeError, "Invalid type");
+ return -1;
+ }
+
+ DBG(FS, pymnt_debug_h(self, "init"));
+
+ if (self->fs)
+ mnt_unref_fs(self->fs);
+
+ self->fs = mnt_new_fs(); /* new FS with refcount=1 */
+
+ if (source && (rc = mnt_fs_set_source(self->fs, source))) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return rc;
+ }
+ if (root && (rc = mnt_fs_set_root(self->fs, root))) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return rc;
+ }
+ if (target && (rc = mnt_fs_set_target(self->fs, target))) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return rc;
+ }
+ if (fstype && (rc = mnt_fs_set_fstype(self->fs, fstype))) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return rc;
+ }
+ if (options && (rc = mnt_fs_set_options(self->fs, options))) {
+ PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
+ return rc;
+ }
+ if (attributes && (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);
+ mnt_fs_set_userdata(self->fs, 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},
+ {"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)
+{
+ const char *src = mnt_fs_get_source(self->fs),
+ *tgt = mnt_fs_get_target(self->fs),
+ *type = mnt_fs_get_fstype(self->fs);
+
+ return PyUnicode_FromFormat(
+ "<libmount.Fs object at %p, "
+ "source=%s, target=%s, fstype=%s>",
+ self,
+ src ? src : "None",
+ tgt ? tgt : "None",
+ type ? type : "None");
+}
+
+PyObject *PyObjectResultFs(struct libmnt_fs *fs)
+{
+ FsObject *result;
+
+ if (!fs) {
+ PyErr_SetString(LibmountError, "internal exception");
+ return NULL;
+ }
+
+ result = mnt_fs_get_userdata(fs);
+ if (result) {
+ Py_INCREF(result);
+ DBG(FS, pymnt_debug_h(fs, "result py-obj %p: already exists, py-refcnt=%d",
+ result, (int) ((PyObject *) result)->ob_refcnt));
+ return (PyObject *) result;
+ }
+
+ /* 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
+ */
+ result = PyObject_New(FsObject, &FsType);
+ if (!result) {
+ UL_RaiseExc(ENOMEM);
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ mnt_ref_fs(fs);
+
+ DBG(FS, pymnt_debug_h(fs, "result py-obj %p new, py-refcnt=%d",
+ result, (int) ((PyObject *) result)->ob_refcnt));
+ result->fs = fs;
+ mnt_fs_set_userdata(fs, 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;
+ DBG(FS, pymnt_debug_h(dest, "copy data"));
+ return (PyObject *)dest;
+
+ } else if (dest == Py_None) { /* create new object */
+ FsObject *result = PyObject_New(FsObject, &FsType);
+
+ DBG(FS, pymnt_debug_h(result, "new copy"));
+ result->fs = mnt_copy_fs(NULL, self->fs);
+ mnt_fs_set_userdata(result->fs, result); /* keep a pointer to encapsulating object */
+ return (PyObject *)result;
+ }
+
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+}
+
+
+PyTypeObject FsType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libmount.Fs", /*tp_name*/
+ sizeof(FsObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Fs_destructor, /*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 FS_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&FsType) < 0)
+ return;
+
+ DBG(FS, pymnt_debug("add to module"));
+ Py_INCREF(&FsType);
+ PyModule_AddObject(mod, "Fs", (PyObject *)&FsType);
+}
+
diff --git a/libmount/python/pylibmount.c b/libmount/python/pylibmount.c
new file mode 100644
index 000000000..c538bb543
--- /dev/null
+++ b/libmount/python/pylibmount.c
@@ -0,0 +1,301 @@
+/*
+ * Python bindings for the libmount library.
+ *
+ * Copyright (C) 2013, Red Hat, Inc. All rights reserved.
+ * Written by Ondrej Oprala and Karel Zak
+ *
+ * This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "pylibmount.h"
+
+/* Libmount-specific Exception class */
+PyObject *LibmountError;
+int pylibmount_debug_mask;
+
+PyObject *UL_IncRef(void *killme)
+{
+ Py_INCREF(killme);
+ return killme;
+}
+
+void PyFree(void *o)
+{
+#if PY_MAJOR_VERSION >= 3
+ Py_TYPE(o)->tp_free((PyObject *)o);
+#else
+ ((PyObject *)o)->ob_type->tp_free((PyObject *)o);
+#endif
+}
+
+/* Demultiplexer for various possible error conditions across the libmount library */
+void *UL_RaiseExc(int e)
+{
+ /* TODO: Do we need to deal with -1/1? */
+ switch (e) {
+ case ENOMEM:
+ PyErr_SetString(PyExc_MemoryError, strerror(e));
+ break;
+ case EINVAL:
+ PyErr_SetString(PyExc_TypeError, strerror(e));
+ break;
+ /* libmount-specific errors */
+ case MNT_ERR_APPLYFLAGS:
+ PyErr_SetString(LibmountError, "Failed to apply MS_PROPAGATION flags");
+ break;
+ case MNT_ERR_MOUNTOPT:
+ PyErr_SetString(LibmountError, "Failed to parse/use userspace mount options");
+ break;
+ case MNT_ERR_NOFSTAB:
+ PyErr_SetString(LibmountError, "Failed to detect filesystem type");
+ break;
+ case MNT_ERR_NOFSTYPE:
+ PyErr_SetString(LibmountError, "Required mount source undefined");
+ break;
+ case MNT_ERR_NOSOURCE:
+ PyErr_SetString(LibmountError, "Loopdev setup failed");
+ break;
+ case MNT_ERR_AMBIFS:
+ PyErr_SetString(LibmountError, "Libblkid detected more filesystems on the device");
+ break;
+ /* some other errno */
+ default:
+ PyErr_SetString(PyExc_Exception, strerror(e));
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * General functions
+ */
+PyObject *PyObjectResultInt(int i)
+{
+ PyObject *result = Py_BuildValue("i", i);
+ if (!result)
+ PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
+ return result;
+}
+
+PyObject *PyObjectResultStr(const char *s)
+{
+ PyObject *result;
+ if (!s)
+ /* TODO: maybe lie about it and return "":
+ * which would allow for
+ * fs = libmount.Fs()
+ * fs.comment += "comment"
+ return Py_BuildValue("s", ""); */
+ Py_RETURN_NONE;
+ result = Py_BuildValue("s", s);
+ if (!result)
+ PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
+ return result;
+}
+
+/* wrapper around a common use case for PyUnicode_AsASCIIString() */
+char *pystos(PyObject *pys)
+{
+#if PY_MAJOR_VERSION >= 3
+ if (!PyUnicode_Check(pys)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+ }
+ return (char *)PyUnicode_1BYTE_DATA(pys);
+#else
+ if (!PyString_Check(pys)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+ }
+ return PyString_AsString(pys);
+#endif
+}
+
+/*
+ * the libmount module
+ */
+#define PYLIBMOUNT_DESC \
+ "Python API for the util-linux libmount library.\n\n" \
+ "Please note that none of the classes' attributes may be deleted.\n" \
+ "This is not a complete mapping to the libmount C API, nor is it\n" \
+ "attempting to be one.\n" "Iterator functions only allow forward\n" \
+ "iteration for now. 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."
+
+
+struct module_state {
+ PyObject *error;
+};
+
+#if PY_MAJOR_VERSION >= 3
+#define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
+#else
+#define GETSTATE(m) (&_state)
+static struct module_state _state;
+#endif
+
+static PyObject *
+error_out(PyObject *m __attribute__((unused))) {
+ struct module_state *st = GETSTATE(m);
+ PyErr_SetString(st->error, "something bad happened");
+ return NULL;
+}
+
+static PyMethodDef pylibmount_methods[] = {
+ {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
+ {NULL, NULL}
+};
+
+#if PY_MAJOR_VERSION >= 3
+
+static int pylibmount_traverse(PyObject *m, visitproc visit, void *arg) {
+ Py_VISIT(GETSTATE(m)->error);
+ return 0;
+}
+
+static int pylibmount_clear(PyObject *m) {
+ Py_CLEAR(GETSTATE(m)->error);
+ return 0;
+}
+
+static struct PyModuleDef moduledef = {
+ PyModuleDef_HEAD_INIT,
+ "pylibmount",
+ NULL,
+ sizeof(struct module_state),
+ pylibmount_methods,
+ NULL,
+ pylibmount_traverse,
+ pylibmount_clear,
+ NULL
+};
+#define INITERROR return NULL
+PyObject * PyInit_pylibmount(void);
+PyObject * PyInit_pylibmount(void)
+#else
+#define INITERROR return
+# ifndef PyMODINIT_FUNC
+# define PyMODINIT_FUNC void
+# endif
+PyMODINIT_FUNC initpylibmount(void);
+PyMODINIT_FUNC initpylibmount(void)
+#endif
+{
+#if PY_MAJOR_VERSION >= 3
+ PyObject *m = PyModule_Create(&moduledef);
+#else
+ PyObject *m = Py_InitModule3("pylibmount", pylibmount_methods, PYLIBMOUNT_DESC);
+#endif
+
+ if (!m)
+ INITERROR;
+ /*
+ * init debug stuff
+ */
+ if (!(pylibmount_debug_mask & PYMNT_DEBUG_INIT)) {
+ char *str = getenv("PYLIBMOUNT_DEBUG");
+
+ pylibmount_debug_mask = 0;
+ if (str)
+ pylibmount_debug_mask = strtoul(str, 0, 0);
+
+ pylibmount_debug_mask |= PYMNT_DEBUG_INIT;
+ }
+
+ if (pylibmount_debug_mask && pylibmount_debug_mask != PYMNT_DEBUG_INIT)
+ DBG(INIT, pymnt_debug("library debug mask: 0x%04x",
+ pylibmount_debug_mask));
+ mnt_init_debug(0);
+
+ /*
+ * Add module objects
+ */
+ LibmountError = PyErr_NewException("libmount.Error", NULL, NULL);
+ Py_INCREF(LibmountError);
+ PyModule_AddObject(m, "Error", (PyObject *)LibmountError);
+
+ FS_AddModuleObject(m);
+ Table_AddModuleObject(m);
+ Context_AddModuleObject(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);
+
+#if PY_MAJOR_VERSION >= 3
+ return m;
+#endif
+}
+
diff --git a/libmount/python/pylibmount.h b/libmount/python/pylibmount.h
new file mode 100644
index 000000000..1a08796dc
--- /dev/null
+++ b/libmount/python/pylibmount.h
@@ -0,0 +1,126 @@
+#ifndef UTIL_LINUX_PYLIBMOUNT_H
+#define UTIL_LINUX_PYLIBMOUNT_H
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "libmount.h"
+
+#define CONFIG_PYLIBMOUNT_DEBUG
+
+#define PYMNT_DEBUG_INIT (1 << 1)
+#define PYMNT_DEBUG_TAB (1 << 2)
+#define PYMNT_DEBUG_FS (1 << 3)
+#define PYMNT_DEBUG_CXT (1 << 4)
+
+#ifdef CONFIG_PYLIBMOUNT_DEBUG
+# include <stdio.h>
+# include <stdarg.h>
+
+# define DBG(m, x) do { \
+ if ((PYMNT_DEBUG_ ## m) & pylibmount_debug_mask) { \
+ fprintf(stderr, "%d: pylibmount: %6s: ", getpid(), # m); \
+ x; \
+ } \
+ } while (0)
+
+extern int pylibmount_debug_mask;
+
+static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
+pymnt_debug(const char *mesg, ...)
+{
+ va_list ap;
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+static inline void __attribute__ ((__format__ (__printf__, 2, 3)))
+pymnt_debug_h(void *handler, const char *mesg, ...)
+{
+ va_list ap;
+
+ if (handler)
+ fprintf(stderr, "[%p]: ", handler);
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+#else /* !CONFIG_PYLIBMOUNT_DEBUG */
+# define DBG(m,x) do { ; } while (0)
+#endif
+
+
+#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 FS_AddModuleObject(PyObject *mod);
+
+/*
+ * tab.c
+ */
+typedef struct {
+ PyObject_HEAD
+
+ struct libmnt_table *tab;
+ struct libmnt_iter *iter;
+ PyObject *errcb;
+} TableObject;
+
+extern PyTypeObject TableType;
+
+extern PyObject *PyObjectResultTab(struct libmnt_table *tab);
+
+extern void Table_unref(struct libmnt_table *tab);
+extern void Table_AddModuleObject(PyObject *mod);
+
+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;
+
+} ContextObjext;
+
+extern PyTypeObject ContextType;
+extern void Context_AddModuleObject(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);
+extern void PyFree(void *o);
+
+
+
+#endif /* UTIL_LINUX_PYLIBMOUNT */
diff --git a/libmount/python/tab.c b/libmount/python/tab.c
new file mode 100644
index 000000000..6f255aef7
--- /dev/null
+++ b/libmount/python/tab.c
@@ -0,0 +1,781 @@
+/*
+ * 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 Table_members[] = {
+ { NULL }
+};
+
+static int Table_set_parser_errcb(TableObject *self, PyObject *func,
+ void *closure __attribute__((unused)))
+{
+ PyObject *tmp;
+
+ if (!func) {
+ PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
+ return -1;
+ }
+
+ if (!PyCallable_Check(func))
+ return -1;
+
+ tmp = self->errcb;
+ Py_INCREF(func);
+ self->errcb = func;
+ Py_XDECREF(tmp);
+ return 0;
+}
+
+static PyObject *Table_get_intro_comment(TableObject *self,
+ void *closure __attribute__((unused)))
+{
+ return PyObjectResultStr(mnt_table_get_intro_comment(self->tab));
+}
+
+static int Table_set_intro_comment(TableObject *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 *Table_get_trailing_comment(TableObject *self,
+ void *closure __attribute__((unused)))
+{
+ return PyObjectResultStr(mnt_table_get_trailing_comment(self->tab));
+}
+
+static int Table_set_trailing_comment(TableObject *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 Table_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 *Table_enable_comments(TableObject *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 Table_replace_file_HELP "replace_file(filename)\n\n" \
+ "This function replaces filename with the new content from TableObject."
+static PyObject *Table_replace_file(TableObject *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;
+ }
+ rc = mnt_table_replace_file(self->tab, filename);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_write_file_HELP "write_file(path)\n\n" \
+ "This function writes tab to file(stream)"
+static PyObject *Table_write_file(TableObject *self, PyObject *args, PyObject *kwds)
+{
+ int rc;
+ //PyObject *stream = NULL;
+ FILE *f = NULL;
+ char *path = NULL;
+ char *kwlist[] = {"path", NULL};
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist,
+ &path)) {
+ PyErr_SetString(PyExc_TypeError, ARG_ERR);
+ return NULL;
+ }
+ if (!(f = fopen(path, "w")))
+ return UL_RaiseExc(errno);
+ rc = mnt_table_write_file(self->tab, f);
+ fclose(f);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_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 *Table_find_devno(TableObject *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 Table_find_mountpoint_HELP "find_mountpoint(path, [direction])\n\n" \
+ "Returns a tab entry or None."
+static PyObject *Table_find_mountpoint(TableObject *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 Table_find_pair_HELP "find_pair(source, target, [direction])\n\n" \
+ "Returns a tab entry or None."
+static PyObject *Table_find_pair(TableObject *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 Table_find_source_HELP "find_source(source, [direction])\n\n" \
+ "Returns a tab entry or None."
+static PyObject *Table_find_source(TableObject *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 Table_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 *Table_find_target(TableObject *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 Table_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 *Table_find_srcpath(TableObject *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 Table_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 *Table_find_tag(TableObject *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 *Table_get_nents(TableObject *self)
+{
+ return PyObjectResultInt(mnt_table_get_nents(self->tab));
+}
+
+#define Table_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 *Table_is_fs_mounted(TableObject *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 Table_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 *Table_parse_file(TableObject *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;
+ }
+ rc = mnt_table_parse_file(self->tab, file);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_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 *Table_parse_fstab(TableObject *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;
+ }
+ rc = mnt_table_parse_fstab(self->tab, fstab);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_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 *Table_parse_mtab(TableObject *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;
+ }
+ rc = mnt_table_parse_mtab(self->tab, mtab);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_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 *Table_parse_dir(TableObject *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;
+ }
+ rc = mnt_table_parse_dir(self->tab, dir);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_parse_swaps_HELP "parse_swaps(swaps)\n\n" \
+ "This function parses /proc/swaps and appends new lines to the tab"
+static PyObject *Table_parse_swaps(TableObject *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;
+ }
+ rc = mnt_table_parse_swaps(self->tab, swaps);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_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 *Table_add_fs(TableObject *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);
+ rc = mnt_table_add_fs(self->tab, fs->fs);
+ return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
+}
+
+#define Table_remove_fs_HELP "remove_fs(fs)\n\n" \
+ "Returns self or raises an exception in case of an error."
+static PyObject *Table_remove_fs(TableObject *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 Table_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}\".format(dir)\n" \
+ "\n" \
+ "</programlisting>\n" \
+ "</informalexample>\n" \
+ "\n" \
+ "lists all mountpoints from fstab in backward order."
+static PyObject *Table_next_fs(TableObject *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 Table_methods[] = {
+ {"enable_comments", (PyCFunction)Table_enable_comments, METH_VARARGS|METH_KEYWORDS, Table_enable_comments_HELP},
+ {"find_pair", (PyCFunction)Table_find_pair, METH_VARARGS|METH_KEYWORDS, Table_find_pair_HELP},
+ {"find_source", (PyCFunction)Table_find_source, METH_VARARGS|METH_KEYWORDS, Table_find_source_HELP},
+ {"find_srcpath", (PyCFunction)Table_find_srcpath, METH_VARARGS|METH_KEYWORDS, Table_find_srcpath_HELP},
+ {"find_tag", (PyCFunction)Table_find_tag, METH_VARARGS|METH_KEYWORDS, Table_find_tag_HELP},
+ {"find_target", (PyCFunction)Table_find_target, METH_VARARGS|METH_KEYWORDS, Table_find_target_HELP},
+ {"find_devno", (PyCFunction)Table_find_devno, METH_VARARGS|METH_KEYWORDS, Table_find_devno_HELP},
+ {"find_mountpoint", (PyCFunction)Table_find_mountpoint, METH_VARARGS|METH_KEYWORDS, Table_find_mountpoint_HELP},
+ {"parse_file", (PyCFunction)Table_parse_file, METH_VARARGS|METH_KEYWORDS, Table_parse_file_HELP},
+ {"parse_fstab", (PyCFunction)Table_parse_fstab, METH_VARARGS|METH_KEYWORDS, Table_parse_fstab_HELP},
+ {"parse_mtab", (PyCFunction)Table_parse_mtab, METH_VARARGS|METH_KEYWORDS, Table_parse_mtab_HELP},
+ {"parse_dir", (PyCFunction)Table_parse_dir, METH_VARARGS|METH_KEYWORDS, Table_parse_dir_HELP},
+ {"parse_swaps", (PyCFunction)Table_parse_swaps, METH_VARARGS|METH_KEYWORDS, Table_parse_swaps_HELP},
+ {"is_fs_mounted", (PyCFunction)Table_is_fs_mounted, METH_VARARGS|METH_KEYWORDS, Table_is_fs_mounted_HELP},
+ {"add_fs", (PyCFunction)Table_add_fs, METH_VARARGS|METH_KEYWORDS, Table_add_fs_HELP},
+ {"remove_fs", (PyCFunction)Table_remove_fs, METH_VARARGS|METH_KEYWORDS, Table_remove_fs_HELP},
+ {"next_fs", (PyCFunction)Table_next_fs, METH_NOARGS, Table_next_fs_HELP},
+ {"write_file", (PyCFunction)Table_write_file, METH_VARARGS|METH_KEYWORDS, Table_write_file_HELP},
+ {"replace_file", (PyCFunction)Table_replace_file, METH_VARARGS|METH_KEYWORDS, Table_replace_file_HELP},
+ {NULL}
+};
+
+/* mnt_free_tab() with a few necessary additions */
+void Table_unref(struct libmnt_table *tab)
+{
+ struct libmnt_fs *fs;
+ struct libmnt_iter *iter;
+
+ if (!tab)
+ return;
+
+ DBG(TAB, pymnt_debug_h(tab, "un-referencing filesystems"));
+
+ iter = mnt_new_iter(MNT_ITER_BACKWARD);
+
+ /* remove pylibmount specific references to the entries */
+ while (mnt_table_next_fs(tab, iter, &fs) == 0)
+ Py_XDECREF(mnt_fs_get_userdata(fs));
+
+ DBG(TAB, pymnt_debug_h(tab, "un-referencing table"));
+
+ mnt_unref_table(tab);
+ mnt_free_iter(iter);
+}
+
+static void Table_destructor(TableObject *self)
+{
+ DBG(TAB, pymnt_debug_h(self->tab, "destrutor py-obj: %p, py-refcnt=%d",
+ self, (int) ((PyObject *) self)->ob_refcnt));
+ Table_unref(self->tab);
+ self->tab = NULL;
+
+ mnt_free_iter(self->iter);
+ Py_XDECREF(self->errcb);
+ PyFree(self);
+}
+
+static PyObject *Table_new(PyTypeObject *type,
+ PyObject *args __attribute__((unused)),
+ PyObject *kwds __attribute__((unused)))
+{
+ TableObject *self = (TableObject*)type->tp_alloc(type, 0);
+
+ if (self) {
+ DBG(TAB, pymnt_debug_h(self, "new"));
+
+ 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 Table_HELP "Table(path=None, errcb=None)"
+static int Table_init(TableObject *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;
+
+ DBG(TAB, pymnt_debug_h(self, "init"));
+
+ Table_unref(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) {
+ PyObject *tmp;
+ if (!PyCallable_Check(errcb))
+ return -1;
+ tmp = self->errcb;
+ Py_INCREF(errcb);
+ self->errcb = errcb;
+ Py_XDECREF(tmp);
+ } else {
+ Py_XDECREF(self->errcb);
+ self->errcb = NULL;
+ }
+
+ if (path) {
+ DBG(TAB, pymnt_debug_h(self, "init: path defined (%s)", 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 {
+ DBG(TAB, pymnt_debug_h(self, "init: allocate empty table"));
+ self->tab = mnt_new_table();
+ }
+
+ /* Always set custom handler when using libmount from python */
+ mnt_table_set_parser_errcb(self->tab, pymnt_table_parser_errcb);
+ mnt_table_set_userdata(self->tab, self);
+
+ cache = mnt_new_cache(); /* TODO: make it optional? */
+ if (!cache)
+ return -1;
+ mnt_table_set_cache(self->tab, cache);
+ mnt_unref_cache(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 *obj;
+
+ obj = mnt_table_get_userdata(tb);
+ if (obj && ((TableObject*) obj)->errcb) {
+ PyObject *arglist, *result;
+
+ arglist = Py_BuildValue("(Osi)", obj, filename, line);
+ if (!arglist)
+ return -ENOMEM;
+
+ /* A python callback was set, so tb is definitely encapsulated in an object */
+ result = PyEval_CallObject(((TableObject *)obj)->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)
+{
+ TableObject *result;
+
+ if (!tab) {
+ PyErr_SetString(LibmountError, "internal exception");
+ return NULL;
+ }
+
+ result = mnt_table_get_userdata(tab);
+ if (result) {
+ Py_INCREF(result);
+ DBG(TAB, pymnt_debug_h(tab, "result py-obj %p: already exists, py-refcnt=%d",
+ result, (int) ((PyObject *) result)->ob_refcnt));
+ return (PyObject *) result;
+ }
+
+ /* 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
+ */
+ result = PyObject_New(TableObject, &TableType);
+ if (!result) {
+ UL_RaiseExc(ENOMEM);
+ return NULL;
+ }
+
+ Py_INCREF(result);
+ mnt_ref_table(tab);
+
+ DBG(TAB, pymnt_debug_h(tab, "result py-obj %p new, py-refcnt=%d",
+ result, (int) ((PyObject *) result)->ob_refcnt));
+ result->tab = tab;
+ result->iter = mnt_new_iter(MNT_ITER_FORWARD);
+ mnt_table_set_userdata(result->tab, result);
+ result->errcb = NULL;
+ return (PyObject *) result;
+}
+
+static PyGetSetDef Table_getseters[] = {
+ {"nents", (getter)Table_get_nents, NULL, "number of valid entries in tab", NULL},
+ {"intro_comment", (getter)Table_get_intro_comment, (setter)Table_set_intro_comment, "fstab intro comment", NULL},
+ {"trailing_comment", (getter)Table_get_trailing_comment, (setter)Table_set_trailing_comment, "fstab trailing comment", NULL},
+ {"errcb", NULL, (setter)Table_set_parser_errcb, "parser error callback", NULL},
+ {NULL}
+};
+
+
+static PyObject *Table_repr(TableObject *self)
+{
+ return PyUnicode_FromFormat(
+ "<libmount.Table object at %p, entries=%d, comments_enabled=%s, errcb=%s>",
+ self,
+ mnt_table_get_nents(self->tab),
+ mnt_table_with_comments(self->tab) ? "True" : "False",
+ self->errcb ? pystos(PyObject_Repr(self->errcb)) : "None");
+}
+
+PyTypeObject TableType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "libmount.Table", /*tp_name*/
+ sizeof(TableObject), /*tp_basicsize*/
+ 0, /*tp_itemsize*/
+ (destructor)Table_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*/
+ Table_HELP, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ Table_methods, /* tp_methods */
+ Table_members, /* tp_members */
+ Table_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)Table_init, /* tp_init */
+ 0, /* tp_alloc */
+ Table_new, /* tp_new */
+};
+
+void Table_AddModuleObject(PyObject *mod)
+{
+ if (PyType_Ready(&TableType) < 0)
+ return;
+
+ DBG(TAB, pymnt_debug("add to module"));
+
+ Py_INCREF(&TableType);
+ PyModule_AddObject(mod, "Table", (PyObject *)&TableType);
+}
+
diff --git a/libmount/python/test_mount_context.py b/libmount/python/test_mount_context.py
new file mode 100755
index 000000000..7aea444b1
--- /dev/null
+++ b/libmount/python/test_mount_context.py
@@ -0,0 +1,173 @@
+import os
+import sys
+import stat
+import errno
+
+# use "import libmount" for in a standard way installed python binding
+import pylibmount as mnt
+
+def usage(tss):
+ print("\nUsage:\n\t{:s} <test> [testoptions]\nTests:\n".format(sys.argv[0]))
+ for i in tss:
+ print("\t{15:-s}".format(i[0]))
+ if i[2] != "":
+ print(" {:s}\n".format(i[2]))
+
+ print("\n")
+ return 1
+
+def mnt_run_test(tss, argv):
+ rc = -1
+ if ((len(argv) < 2) or (argv[1] == "--help") or (argv[1] == "-h")):
+ return usage(tss)
+
+ #mnt_init_debug(0)
+
+ i=()
+ for i in tss:
+ if i[0] == argv[1]:
+ rc = i[1](i, argv[1:])
+ if rc:
+ print("FAILED [rc={:d}]".format(rc))
+ break
+
+ if ((rc < 0) and (i == ())):
+ return usage(tss)
+ return not not rc #because !!rc is too mainstream for python
+
+def test_mount(ts, argv):
+ idx = 1
+ rc = 0
+
+ if len(argv) < 2:
+ return -errno.EINVAL
+
+ cxt = mnt.Context()
+
+ if argv[idx] == "-o":
+ cxt.options = argv[idx+1]
+ idx += 2
+ if argv[idx] == "-t":
+ cxt.fstype = argv[idx+1]
+ idx += 2
+ if len(argv) == idx + 1:
+ cxt.target = argv[idx]
+ idx+=1
+ elif (len(argv) == idx + 2):
+ cxt.source = argv[idx]
+ idx += 1
+ cxt.target = argv[idx]
+ idx += 1
+
+ try:
+ cxt.mount()
+ except Exception:
+ print("failed to mount")
+ return -1
+ print("successfully mounted")
+ return rc
+
+def test_umount(ts, argv):
+ idx = 1
+ rc = 0
+ if len(argv) < 2:
+ return -errno.EINVAL
+
+ cxt = mnt.Context()
+
+ if argv[idx] == "-t":
+ cxt.options = argv[idx+1]
+ idx += 2
+
+ if argv[idx] == "-f":
+ cxt.enable_force(True)
+
+ if argv[idx] == "-l":
+ cxt.enable_lazy(True)
+ idx += 1
+ elif argv[idx] == "-r":
+ cxt.enable_rdonly_umount(True)
+ idx += 1
+
+ if len(argv) == idx + 1:
+ cxt.target = argv[idx]
+ idx += 1
+ else:
+ return -errno.EINVAL
+ try:
+ cxt.umount()
+ except Exception:
+ print("failed to umount")
+ return 1
+ print("successfully umounted")
+ return rc
+
+def test_flags(ts, argv):
+ idx = 1
+ rc = 0
+ opt = ""
+ flags = 0
+ cxt = mnt.Context()
+
+ if argv[idx] == "-o":
+ cxt.options = argv[idx + 1]
+ idx += 2
+ if len(argv) == idx + 1:
+ cxt.target = argv[idx]
+ idx += 1
+
+ try:
+ cxt.prepare_mount()
+ # catch ioerror here
+ except IOError as e:
+ print("failed to prepare mount {:s}".format(e.strerror))
+
+ opt = cxt.fs.options
+ if (opt):
+ print("options: {:s}", opt)
+
+ print("flags: {08:lx}".format(cxt.mflags()))
+ return rc
+
+def test_mountall(ts, argv):
+ mntrc = 1
+ ignored = 1
+ idx = 1
+ cxt = mnt.Context()
+
+ if len(argv) > 2:
+ if argv[idx] == "-O":
+ cxt.options_pattern = argv[idx+1]
+ idx += 2
+ if argv[idx] == "-t":
+ cxt.fstype_pattern = argv[idx+1]
+ idx += 2
+
+ i = ()
+ while (cxt.next_mount()):
+ tgt = i.target
+ if (ignored == 1):
+ print("{:s}: ignored: not match".format(tgt))
+ elif (ignored == 2):
+ print("{:s}: ignored: already mounted".format(tgt))
+ elif (not cxt.status):
+ if (mntrc > 0):
+ # ?? errno = mntrc
+ print("{:s}: mount failed".format(tgt))
+ else:
+ print("{:s}: mount failed".format(tgt))
+ else:
+ print("{:s}: successfully mounted".format(tgt))
+
+ return 0
+
+
+tss = (
+ ( "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" ),
+ ( "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" ),
+ ( "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" ),
+ ( "--flags", test_flags, "[-o <opts>] <spec>" )
+)
+os.umask(stat.S_IWGRP | stat.S_IWOTH) #to be compatible with mount(8)
+
+sys.exit(mnt_run_test(tss, sys.argv))
diff --git a/libmount/python/test_mount_tab.py b/libmount/python/test_mount_tab.py
new file mode 100755
index 000000000..1f63b9554
--- /dev/null
+++ b/libmount/python/test_mount_tab.py
@@ -0,0 +1,164 @@
+import os
+import sys
+import stat
+import errno
+import functools as ft
+
+# use "import libmount" for in a standard way installed python binding
+import pylibmount as mnt
+
+def usage(tss):
+ print("\nUsage:\n\t{:s} <test> [testoptions]\nTests:\n".format(sys.argv[0]))
+ for i in tss:
+ print("\t{15:-s}".format(i[0]))
+ if i[2] != "":
+ print(" {:s}\n".format(i[2]))
+
+ print("\n")
+ return 1
+
+def mnt_run_test(tss, argv):
+ rc = -1
+ if ((len(argv) < 2) or (argv[1] == "--help") or (argv[1] == "-h")):
+ return usage(tss)
+
+ #mnt_init_debug(0)
+
+ i=()
+ for i in tss:
+ if i[0] == argv[1]:
+ rc = i[1](i, argv[1:])
+ if rc:
+ print("FAILED [rc={:d}]".format(rc))
+ break
+
+ if ((rc < 0) and (i == ())):
+ return usage(tss)
+ return not not rc #because !!rc is too mainstream for python
+
+def parser_errcb(tb, fname, line):
+ print("{:s}:{:d}: parse error".format(fname, line))
+ return 1
+
+def create_table(f, comments):
+ if not f:
+ return None
+
+ tb = mnt.Table()
+ tb.enable_comments(comments)
+ tb.errcb = parser_errcb
+
+ try:
+ tb.parse_file(f)
+ except Exception:
+ print("{:s}: parsing failed".format(f))
+ return None
+ return tb
+
+def test_copy_fs(ts, argv):
+ rc = -1
+ tb = create_table(argv[1], False)
+ fs = tb.find_target("/", mnt.MNT_ITER_FORWARD)
+ if not fs:
+ return rc
+
+ print("ORIGINAL:")
+ fs.print_debug()
+
+ fs = fs.copy_fs(None)
+ if not fs:
+ return rc
+ print("COPY:")
+ fs.print_debug()
+ return 0
+
+def test_parse(ts, argv):
+ parse_comments = False
+
+ if len(argv) == 3 and argv[2] == "--comments":
+ parse_comments = True
+ tb = create_table(argv[1], parse_comments)
+
+ if tb.intro_comment:
+ print("Initial comment:\n\"{:s}\"".format(tb.intro_comment))
+ #while ((fs = tb.next_fs()) != None):
+ for fs in iter(ft.partial(tb.next_fs), None):
+ fs.print_debug()
+ if tb.trailing_comment:
+ print("Trailing comment:\n\"{:s}\"".format(tb.trailing_comment))
+ return 0
+
+def test_find(ts, argv, dr):
+ if len(argv) != 4:
+ print("try --help")
+ return -errno.EINVAL
+
+ f, find, what = argv[1:]
+
+ tb = create_table(f, False)
+ if find.lower() == "source":
+ fs = tb.find_source(what, dr)
+ elif find.lower() == "target":
+ fs = tb.find_target(what, dr)
+
+ if not fs:
+ print("{:s}: not found {:s} '{:s}'".format(f, find, what))
+ else:
+ fs.print_debug()
+ return 0
+
+def test_find_fw(ts, argv):
+ return test_find(ts, argv, mnt.MNT_ITER_FORWARD)
+
+def test_find_bw(ts, argv):
+ return test_find(ts, argv, mnt.MNT_ITER_BACKWARD)
+
+def test_find_pair(ts, argv):
+ rc = -1
+ tb = create_table(argv[1], False)
+ fs = tb.find_pair(argv[2], argv[3], mnt.MNT_ITER_FORWARD)
+ if not fs:
+ return rc
+ fs.print_debug()
+ return 0
+
+def test_is_mounted(ts, argv):
+ rc = -1
+ tb = mnt.Tab(path="/proc/self/mountinfo")
+ if not tb:
+ print("failed to parse mountinto")
+ return rc
+
+ fstab = create_table(argv[1], False)
+ if not fstab:
+ return rc
+ fs = ()
+ for fs in ft.iter(tb.next_fs(), -1):
+ if tb.is_fs_mounted(fs):
+ print("{:s} already mounted on {:s}".format(fs.source, fs.target))
+ else:
+ print("{:s} not mounted on {:s}".format(fs.source, fs.target))
+ return 0
+
+def test_find_mountpoint(ts, argv):
+ rc = -1
+ tb = mnt.Table("/proc/self/mountinfo")
+ if not tb:
+ return rc
+ fs = tb.find_mountpoint(argv[1], mnt.MNT_ITER_BACKWARD)
+ if not fs:
+ return rc
+ fs.print_debug()
+ return 0
+
+
+tss = (
+ ( "--parse", test_parse, "<file> [--comments] parse and print(tab" ),
+ ( "--find-forward", test_find_fw, "<file> <source|target> <string>" ),
+ ( "--find-backward", test_find_bw, "<file> <source|target> <string>" ),
+ ( "--find-pair", test_find_pair, "<file> <source> <target>" ),
+ ( "--find-mountpoint", test_find_mountpoint, "<path>" ),
+ ( "--copy-fs", test_copy_fs, "<file> copy root FS from the file" ),
+ ( "--is-mounted", test_is_mounted, "<fstab> check what from <file> are already mounted" ),
+)
+sys.exit(mnt_run_test(tss, sys.argv))
diff --git a/libmount/python/test_mount_tab_update.py b/libmount/python/test_mount_tab_update.py
new file mode 100755
index 000000000..a16e9e341
--- /dev/null
+++ b/libmount/python/test_mount_tab_update.py
@@ -0,0 +1,59 @@
+import os
+import sys
+import stat
+import errno
+
+# use "import libmount" for in a standard way installed python binding
+import pylibmount as mnt
+
+def usage(tss):
+ print("\nUsage:\n\t{:s} <test> [testoptions]\nTests:\n".format(sys.argv[0]))
+ for i in tss:
+ print("\t{15:-s}".format(i[0]))
+ if i[2] != "":
+ print(" {:s}\n".format(i[2]))
+
+ print("\n")
+ return 1
+
+def mnt_run_test(tss, argv):
+ rc = -1
+ if ((len(argv) < 2) or (argv[1] == "--help") or (argv[1] == "-h")):
+ return usage(tss)
+
+ #mnt_init_debug(0)
+
+ i=()
+ for i in tss:
+ if i[0] == argv[1]:
+ rc = i[1](i, argv[1:])
+ if rc:
+ print("FAILED [rc={:d}]".format(rc))
+ break
+
+ if ((rc < 0) and (i == ())):
+ return usage(tss)
+ return not not rc #because !!rc is too mainstream for python
+
+def test_replace(ts, argv):
+ fs = mnt.Fs()
+ tb = mnt.Table()
+
+ if (len(argv) < 3):
+ return -1
+ tb.enable_comments(True)
+ tb.parse_fstab()
+
+ fs.source = argv[1]
+ fs.target = argv[2]
+ #TODO: resolve None + string
+ fs.comment = "# this is new filesystem\n"
+ tb.add_fs(fs)
+ tb.replace_file(os.environ["LIBMOUNT_FSTAB"])
+ return 0
+
+tss = (
+ ( "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" ),
+)
+
+sys.exit(mnt_run_test(tss, sys.argv))
diff --git a/libmount/src/Makemodule.am b/libmount/src/Makemodule.am
index 494e02a34..9101811f5 100644
--- a/libmount/src/Makemodule.am
+++ b/libmount/src/Makemodule.am
@@ -26,23 +26,26 @@ libmount_la_SOURCES = \
libmount/src/test.c \
libmount/src/utils.c \
libmount/src/version.c \
- $(mountinc_HEADERS)
+ $(nodist_mountinc_HEADERS)
nodist_libmount_la_SOURCES = libmount/src/mountP.h
libmount_la_LIBADD = libcommon.la libblkid.la $(SELINUX_LIBS)
libmount_la_CFLAGS = \
+ $(SOLIB_CFLAGS) \
-I$(ul_libblkid_incdir) \
-I$(ul_libmount_incdir) \
-I$(top_srcdir)/libmount/src
libmount_la_DEPENDENCIES = \
- $(libmount_la_LIBADD) \
+ libcommon.la \
+ libblkid.la \
libmount/src/libmount.sym \
libmount/src/libmount.h.in
libmount_la_LDFLAGS = \
+ $(SOLIB_LDFLAGS) \
-Wl,--version-script=$(top_srcdir)/libmount/src/libmount.sym \
-version-info $(LIBMOUNT_VERSION_INFO)
diff --git a/libmount/src/cache.c b/libmount/src/cache.c
index 7b651228a..92f469456 100644
--- a/libmount/src/cache.c
+++ b/libmount/src/cache.c
@@ -10,7 +10,7 @@
* @title: Cache
* @short_description: paths and tags (UUID/LABEL) caching
*
- * The cache is a very simple API for work with tags (LABEL, UUID, ...) and
+ * The cache is a very simple API for working with tags (LABEL, UUID, ...) and
* paths. The cache uses libblkid as a backend for TAGs resolution.
*
* All returned paths are always canonicalized.
@@ -48,6 +48,7 @@ struct libmnt_cache {
struct mnt_cache_entry *ents;
size_t nents;
size_t nallocs;
+ int refcount;
/* blkid_evaluate_tag() works in two ways:
*
@@ -72,6 +73,7 @@ struct libmnt_cache *mnt_new_cache(void)
if (!cache)
return NULL;
DBG(CACHE, mnt_debug_h(cache, "alloc"));
+ cache->refcount = 1;
return cache;
}
@@ -79,7 +81,8 @@ struct libmnt_cache *mnt_new_cache(void)
* mnt_free_cache:
* @cache: pointer to struct libmnt_cache instance
*
- * Deallocates the cache.
+ * Deallocates the cache. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_cache().
*/
void mnt_free_cache(struct libmnt_cache *cache)
{
@@ -89,6 +92,7 @@ void mnt_free_cache(struct libmnt_cache *cache)
return;
DBG(CACHE, mnt_debug_h(cache, "free"));
+ WARN_REFCOUNT(CACHE, cache, cache->refcount);
for (i = 0; i < cache->nents; i++) {
struct mnt_cache_entry *e = &cache->ents[i];
@@ -102,7 +106,39 @@ void mnt_free_cache(struct libmnt_cache *cache)
free(cache);
}
-/* note that the @key could be tha same pointer as @value */
+/**
+ * mnt_ref_cache:
+ * @cache: cache pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_cache(struct libmnt_cache *cache)
+{
+ if (cache) {
+ cache->refcount++;
+ /*DBG(CACHE, mnt_debug_h(cache, "ref=%d", cache->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_cache:
+ * @cache: cache pointer
+ *
+ * De-increments reference counter, on zero the cache is automatically
+ * deallocated by mnt_free_cache().
+ */
+void mnt_unref_cache(struct libmnt_cache *cache)
+{
+ if (cache) {
+ cache->refcount--;
+ /*DBG(CACHE, mnt_debug_h(cache, "unref=%d", cache->refcount));*/
+ if (cache->refcount <= 0)
+ mnt_free_cache(cache);
+ }
+}
+
+
+/* note that the @key could be the same pointer as @value */
static int cache_add_entry(struct libmnt_cache *cache, char *key,
char *value, int flag)
{
@@ -135,7 +171,7 @@ static int cache_add_entry(struct libmnt_cache *cache, char *key,
return 0;
}
-/* add tag to the cache, @devname has to be allocated string */
+/* add tag to the cache, @devname has to be an allocated string */
static int cache_add_tag(struct libmnt_cache *cache, const char *tagname,
const char *tagval, char *devname, int flag)
{
@@ -270,13 +306,13 @@ int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname)
DBG(CACHE, mnt_debug_h(cache, "tags for %s requested", devname));
- /* check is device is already cached */
+ /* check if device is already cached */
for (i = 0; i < cache->nents; i++) {
struct mnt_cache_entry *e = &cache->ents[i];
if (!(e->flag & MNT_CACHE_TAGREAD))
continue;
if (strcmp(e->value, devname) == 0)
- /* tags has been already read */
+ /* tags have already been read */
return 0;
}
@@ -335,7 +371,7 @@ error:
* @token: tag name (e.g "LABEL")
* @value: tag value
*
- * Look up @cache to check it @tag+@value are associated with @devname.
+ * Look up @cache to check if @tag+@value are associated with @devname.
*
* Returns: 1 on success or 0.
*/
@@ -421,7 +457,7 @@ char *mnt_get_fstype(const char *devname, int *ambi, struct libmnt_cache *cache)
rc = blkid_do_safeprobe(pr);
- DBG(CACHE, mnt_debug_h(cache, "liblkid rc=%d", rc));
+ DBG(CACHE, mnt_debug_h(cache, "libblkid rc=%d", rc));
if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL))
type = strdup(data);
@@ -493,7 +529,7 @@ error:
* - /dev/loopN to the loop backing filename
* - empty path (NULL) to 'none'
*
- * Returns: new allocated string with path, result has to be always deallocated
+ * Returns: newly allocated string with path, result always has to be deallocated
* by free().
*/
char *mnt_pretty_path(const char *path, struct libmnt_cache *cache)
@@ -583,22 +619,18 @@ error:
char *mnt_resolve_spec(const char *spec, struct libmnt_cache *cache)
{
char *cn = NULL;
+ char *t = NULL, *v = NULL;
if (!spec)
return NULL;
- if (strchr(spec, '=')) {
- char *tag, *val;
-
- if (!blkid_parse_tag_string(spec, &tag, &val)) {
- cn = mnt_resolve_tag(tag, val, cache);
-
- free(tag);
- free(val);
- }
- } else
+ if (blkid_parse_tag_string(spec, &t, &v) == 0 && mnt_valid_tagname(t))
+ cn = mnt_resolve_tag(t, v, cache);
+ else
cn = mnt_resolve_path(spec, cache);
+ free(t);
+ free(v);
return cn;
}
@@ -624,7 +656,7 @@ int test_resolve_path(struct libmnt_test *ts, int argc, char *argv[])
p = mnt_resolve_path(line, cache);
printf("%s : %s\n", line, p);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
@@ -647,7 +679,7 @@ int test_resolve_spec(struct libmnt_test *ts, int argc, char *argv[])
p = mnt_resolve_spec(line, cache);
printf("%s : %s\n", line, p);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
@@ -663,6 +695,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
while(fgets(line, sizeof(line), stdin)) {
size_t sz = strlen(line);
+ char *t = NULL, *v = NULL;
if (sz > 0 && line[sz - 1] == '\n')
line[sz - 1] = '\0';
@@ -674,16 +707,14 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
if (mnt_cache_read_tags(cache, line) < 0)
fprintf(stderr, "%s: read tags failed\n", line);
- } else if (strchr(line, '=')) {
- char *tag, *val;
+ } else if (blkid_parse_tag_string(line, &t, &v) == 0) {
const char *cn = NULL;
- if (!blkid_parse_tag_string(line, &tag, &val)) {
- cn = cache_find_tag(cache, tag, val);
+ if (mnt_valid_tagname(t))
+ cn = cache_find_tag(cache, t, v);
+ free(t);
+ free(v);
- free(tag);
- free(val);
- }
if (cn)
printf("%s: %s\n", line, cn);
else
@@ -700,7 +731,7 @@ int test_read_tags(struct libmnt_test *ts, int argc, char *argv[])
e->key + strlen(e->key) + 1);
}
- mnt_free_cache(cache);
+ mnt_unref_cache(cache);
return 0;
}
diff --git a/libmount/src/context.c b/libmount/src/context.c
index af16f6472..8dca3c12a 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -89,10 +89,8 @@ void mnt_free_context(struct libmnt_context *cxt)
free(cxt->fstype_pattern);
free(cxt->optstr_pattern);
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
+ mnt_unref_table(cxt->fstab);
+ mnt_unref_cache(cxt->cache);
mnt_context_clear_loopdev(cxt);
mnt_free_lock(cxt->lock);
@@ -108,11 +106,11 @@ void mnt_free_context(struct libmnt_context *cxt)
* mnt_reset_context:
* @cxt: mount context
*
- * Resets all information in the context that are directly related to
- * the latest mount (spec, source, target, mount options, ....)
+ * Resets all information in the context that is directly related to
+ * the latest mount (spec, source, target, mount options, ...).
*
- * The match patters, cached fstab, cached canonicalized paths and tags and
- * [e]uid are not reseted. You have to use
+ * The match patterns, cached fstab, cached canonicalized paths and tags and
+ * [e]uid are not reset. You have to use
*
* mnt_context_set_fstab(cxt, NULL);
* mnt_context_set_cache(cxt, NULL);
@@ -120,7 +118,7 @@ void mnt_free_context(struct libmnt_context *cxt)
* mnt_context_set_options_pattern(cxt, NULL);
*
*
- * to reset these stuff.
+ * to reset this stuff.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -136,10 +134,8 @@ int mnt_reset_context(struct libmnt_context *cxt)
fl = cxt->flags;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
-
- mnt_free_table(cxt->mtab);
+ mnt_unref_fs(cxt->fs);
+ mnt_unref_table(cxt->mtab);
free(cxt->helper);
free(cxt->orig_user);
@@ -164,9 +160,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
mnt_context_reset_status(cxt);
mnt_context_set_tabfilter(cxt, NULL, NULL);
- /* restore non-resetable flags */
- cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB);
- cxt->flags |= (fl & MNT_FL_EXTERN_CACHE);
+ /* restore non-resettable flags */
cxt->flags |= (fl & MNT_FL_NOMTAB);
cxt->flags |= (fl & MNT_FL_FAKE);
cxt->flags |= (fl & MNT_FL_SLOPPY);
@@ -225,7 +219,7 @@ static int set_flag(struct libmnt_context *cxt, int flag, int enable)
* mnt_context_is_restricted:
* @cxt: mount context
*
- * Returns: 0 for unrestricted mount (user is root), or 1 for non-root mounts
+ * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
*/
int mnt_context_is_restricted(struct libmnt_context *cxt)
{
@@ -235,9 +229,9 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
/**
* mnt_context_set_optsmode
* @cxt: mount context
- * @mode: MNT_OMASK_* flags
+ * @mode: MNT_OMODE_* flags
*
- * Controls how to use mount optionsmsource and target paths from fstab/mtab.
+ * Controls how to use mount optionssource and target paths from fstab/mtab.
*
* @MNT_OMODE_IGNORE: ignore mtab/fstab options
*
@@ -247,7 +241,7 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
*
* @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
*
- * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target is defined)
+ * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
*
* @MNT_OMODE_FSTAB: read from fstab
*
@@ -262,8 +256,8 @@ int mnt_context_is_restricted(struct libmnt_context *cxt)
* Notes:
*
* - MNT_OMODE_USER is always used if mount context is in restricted mode
- * - MNT_OMODE_AUTO is used if nothing other is defined
- * - the flags are eavaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
+ * - MNT_OMODE_AUTO is used if nothing else is defined
+ * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
* MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
* are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
*
@@ -282,7 +276,7 @@ int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
* mnt_context_get_optsmode
* @cxt: mount context
*
- * Returns: MNT_OMASK_* mask or zero.
+ * Returns: MNT_OMODE_* mask or zero.
*/
int mnt_context_get_optsmode(struct libmnt_context *cxt)
@@ -297,12 +291,12 @@ int mnt_context_get_optsmode(struct libmnt_context *cxt)
* @disable: TRUE or FALSE
*
* Enable/disable paths canonicalization and tags evaluation. The libmount context
- * canonicalies paths when search in fstab and when prepare source and target paths
+ * canonicalizes paths when searching in fstab and when preparing source and target paths
* for mount(2) syscall.
*
- * This fuction has effect to the private (within context) fstab instance only
+ * This fuction has an effect on the private (within context) fstab instance only
* (see mnt_context_set_fstab()). If you want to use an external fstab then you
- * need manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
+ * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
* NULL).
*
* Returns: 0 on success, negative number in case of error.
@@ -316,7 +310,7 @@ int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
* mnt_context_is_nocanonicalize:
* @cxt: mount context
*
- * Returns: 1 if no-canonicalize mode enabled or 0.
+ * Returns: 1 if no-canonicalize mode is enabled or 0.
*/
int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
{
@@ -389,10 +383,13 @@ int mnt_context_is_parent(struct libmnt_context *cxt)
* mnt_context_is_child:
* @cxt: mount context
*
- * Return: 1 if mount -F enabled and the current context is child, or 0
+ * Return: 1 f the current context is child, or 0
*/
int mnt_context_is_child(struct libmnt_context *cxt)
{
+ /* See mnt_fork_context(), the for fork flag is always disabled
+ * for children to avoid recursive forking.
+ */
return !mnt_context_is_fork(cxt) && cxt->pid;
}
@@ -415,7 +412,7 @@ int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
* mnt_context_is_rdonly_umount
* @cxt: mount context
*
- * See also mnt_context_enable_rdonly_umount() and see umount(8) man page,
+ * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
* option -r.
*
* Returns: 1 if read-only remount failed umount(2) is enables or 0
@@ -607,7 +604,7 @@ int mnt_context_is_verbose(struct libmnt_context *cxt)
* @cxt: mount context
* @enable: TRUE or FALSE
*
- * Enable/disable loop delete (destroy) after umount (see umount(8), option -d)
+ * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -633,12 +630,13 @@ int mnt_context_is_loopdel(struct libmnt_context *cxt)
* @fs: filesystem description
*
* The mount context uses private @fs by default. This function allows to
- * overwrite the private @fs with an external instance. Note that the external
- * @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
+ * overwrite the private @fs with an external instance. This function
+ * increments @fs reference counter (and deincrement reference counter of the
+ * old fs).
*
* The @fs will be modified by mnt_context_set_{source,target,options,fstype}
- * functions, If the @fs is NULL then all current FS specific setting (source,
- * target, etc., exclude spec) is reseted.
+ * functions, If the @fs is NULL, then all current FS specific settings (source,
+ * target, etc., exclude spec) are reset.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -646,10 +644,9 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FS))
- mnt_free_fs(cxt->fs);
- set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
+ mnt_ref_fs(fs); /* new */
+ mnt_unref_fs(cxt->fs); /* old */
cxt->fs = fs;
return 0;
}
@@ -662,25 +659,64 @@ int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
* Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
* functions.
*
- * Returns: pointer to FS description or NULL in case of calloc() errrr.
+ * Returns: pointer to FS description or NULL in case of a calloc() error.
*/
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
{
assert(cxt);
if (!cxt)
return NULL;
- if (!cxt->fs) {
+ if (!cxt->fs)
cxt->fs = mnt_new_fs();
- cxt->flags &= ~MNT_FL_EXTERN_FS;
- }
return cxt->fs;
}
/**
+ * mnt_context_get_fs_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
+}
+
+/**
+ * mnt_context_get_fstab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
+}
+
+/**
+ * mnt_context_get_mtab_userdata:
+ * @cxt: mount context
+ *
+ * Returns: pointer to userdata or NULL.
+ */
+void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
+{
+ assert(cxt);
+ return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
+}
+
+/**
* mnt_context_set_source:
* @cxt: mount context
* @source: mount source (device, directory, UUID, LABEL, ...)
*
+ * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
+ * mount option. The real return code is always returned, when
+ * the device does not exist then it's usually MNT_ERR_NOSOURCE
+ * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
+ *
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
@@ -693,7 +729,7 @@ int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
* mnt_context_get_source:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_source(struct libmnt_context *cxt)
{
@@ -718,7 +754,7 @@ int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
* mnt_context_get_target:
* @cxt: mount context
*
- * Returns: returns pointer or NULL in case of error pr if not set.
+ * Returns: returns pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_target(struct libmnt_context *cxt)
{
@@ -731,8 +767,8 @@ const char *mnt_context_get_target(struct libmnt_context *cxt)
* @cxt: mount context
* @fstype: filesystem type
*
- * Note that the @fstype has to be the real FS type. For patterns with
- * comma-separated list of filesystems or for "nofs" notation use
+ * Note that the @fstype has to be a FS type. For patterns with
+ * comma-separated list of filesystems or for the "nofs" notation, use
* mnt_context_set_fstype_pattern().
*
* Returns: 0 on success, negative number in case of error.
@@ -747,7 +783,7 @@ int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
* mnt_context_get_fstype:
* @cxt: mount context
*
- * Returns: pointer or NULL in case of error pr if not set.
+ * Returns: pointer or NULL in case of error or if not set.
*/
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
{
@@ -788,8 +824,8 @@ int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
* This function returns mount options set by mnt_context_set_options() or
* mnt_context_append_options().
*
- * Note that *after* mnt_context_prepare_mount() may the mount options string
- * also includes options set by mnt_context_set_mflags() or another options
+ * Note that *after* mnt_context_prepare_mount(), the mount options string
+ * may also include options set by mnt_context_set_mflags() or other options
* generated by this library.
*
* Returns: pointer or NULL
@@ -857,15 +893,19 @@ int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *patt
* @cxt: mount context
* @tb: fstab
*
- * The mount context reads /etc/fstab to the the private struct libmnt_table by default.
+ * The mount context reads /etc/fstab to the private struct libmnt_table by default.
* This function allows to overwrite the private fstab with an external
- * instance. Note that the external instance is not deallocated by mnt_free_context().
+ * instance.
+ *
+ * This function modify the @tb reference counter. This function does not set
+ * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
+ * mnt_context_get_cache(cxt));
*
* The fstab is used read-only and is not modified, it should be possible to
- * share the fstab between more mount contexts (TODO: tests it.)
+ * share the fstab between more mount contexts (TODO: test it.)
*
- * If the @tb argument is NULL then the current private fstab instance is
- * reseted.
+ * If the @tb argument is NULL, then the current private fstab instance is
+ * reset.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -874,10 +914,10 @@ int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
assert(cxt);
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_free_table(cxt->fstab);
- set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
+ mnt_ref_table(tb); /* new */
+ mnt_unref_table(cxt->fstab); /* old */
+
cxt->fstab = tb;
return 0;
}
@@ -893,8 +933,6 @@ int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
*/
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
assert(cxt);
if (!cxt)
return -EINVAL;
@@ -906,18 +944,12 @@ int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
return -ENOMEM;
if (cxt->table_errcb)
mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
- cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
+ mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
rc = mnt_table_parse_fstab(cxt->fstab, NULL);
if (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
-
- /* never touch an external fstab */
- if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
- mnt_table_set_cache(cxt->fstab, cache);
-
if (tb)
*tb = cxt->fstab;
return 0;
@@ -929,14 +961,12 @@ int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
* @tb: returns mtab
*
* See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
- * result will deallocated by mnt_free_context(@cxt).
+ * result will be deallocated by mnt_free_context(@cxt).
*
* Returns: 0 on success, negative number in case of error.
*/
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
-
assert(cxt);
if (!cxt)
return -EINVAL;
@@ -954,14 +984,12 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
cxt->table_fltrcb,
cxt->table_fltrcb_data);
+ mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
if (rc)
return rc;
}
- cache = mnt_context_get_cache(cxt);
- mnt_table_set_cache(cxt->mtab, cache);
-
if (tb)
*tb = cxt->mtab;
@@ -971,8 +999,8 @@ int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
}
/*
- * Allows to specify filter for tab file entries. The filter is called by
- * table parser. Currently used for mtab and utab only.
+ * Allows to specify a filter for tab file entries. The filter is called by
+ * the table parser. Currently used for mtab and utab only.
*/
int mnt_context_set_tabfilter(struct libmnt_context *cxt,
int (*fltr)(struct libmnt_fs *, void *),
@@ -1004,7 +1032,7 @@ int mnt_context_set_tabfilter(struct libmnt_context *cxt,
* callback and cache for tags and paths is set according to the @cxt setting.
* See also mnt_table_parse_file().
*
- * It's strongly recommended use mnt_context_get_mtab() and
+ * It's strongly recommended to use the mnt_context_get_mtab() and
* mnt_context_get_fstab() functions for mtab and fstab files. This function
* does not care about LIBMOUNT_* env.variables and does not merge userspace
* options.
@@ -1016,7 +1044,6 @@ int mnt_context_set_tabfilter(struct libmnt_context *cxt,
int mnt_context_get_table(struct libmnt_context *cxt,
const char *filename, struct libmnt_table **tb)
{
- struct libmnt_cache *cache;
int rc;
assert(cxt);
@@ -1033,14 +1060,11 @@ int mnt_context_get_table(struct libmnt_context *cxt,
rc = mnt_table_parse_file(*tb, filename);
if (rc) {
- mnt_free_table(*tb);
+ mnt_unref_table(*tb);
return rc;
}
- cache = mnt_context_get_cache(cxt);
- if (cache)
- mnt_table_set_cache(*tb, cache);
-
+ mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
return 0;
}
@@ -1065,6 +1089,11 @@ int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
if (!cxt)
return -EINVAL;
+ if (cxt->mtab)
+ mnt_table_set_parser_errcb(cxt->mtab, cb);
+ if (cxt->fstab)
+ mnt_table_set_parser_errcb(cxt->fstab, cb);
+
cxt->table_errcb = cb;
return 0;
}
@@ -1074,12 +1103,15 @@ int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
* @cxt: mount context
* @cache: cache instance or nULL
*
- * The mount context maintains a private struct libmnt_cache by default. This function
- * allows to overwrite the private cache with an external instance. Note that
- * the external instance is not deallocated by mnt_free_context().
+ * The mount context maintains a private struct libmnt_cache by default. This
+ * function allows to overwrite the private cache with an external instance.
+ * This function increments cache reference counter.
*
- * If the @cache argument is NULL then the current private cache instance is
- * reseted.
+ * If the @cache argument is NULL, then the current cache instance is reset.
+ * This function apply the cache to fstab and mtab instances (if already
+ * exists).
+ *
+ * The old cache instance reference counter is de-incremented.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1087,11 +1119,17 @@ int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache
{
if (!cxt)
return -EINVAL;
- if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
- mnt_free_cache(cxt->cache);
- set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
+ mnt_ref_cache(cache); /* new */
+ mnt_unref_cache(cxt->cache); /* old */
+
cxt->cache = cache;
+
+ if (cxt->mtab)
+ mnt_table_set_cache(cxt->mtab, cache);
+ if (cxt->fstab)
+ mnt_table_set_cache(cxt->fstab, cache);
+
return 0;
}
@@ -1110,10 +1148,9 @@ struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
return NULL;
if (!cxt->cache) {
- cxt->cache = mnt_new_cache();
- if (!cxt->cache)
- return NULL;
- cxt->flags &= ~MNT_FL_EXTERN_CACHE;
+ struct libmnt_cache *cache = mnt_new_cache();
+ mnt_context_set_cache(cxt, cache);
+ mnt_unref_cache(cache);
}
return cxt->cache;
}
@@ -1125,7 +1162,7 @@ struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
* @release: callback to release (delallocate) password
*
* Sets callbacks for encryption password (e.g encrypted loopdev). This
- * function is deprecated (encrypted loops are no ore supported).
+ * function is deprecated (encrypted loops are no longer supported).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1151,7 +1188,7 @@ int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
*
* The default behavior is to ignore all signals (except SIGALRM and
* SIGTRAP for mtab udate) when the lock is locked. If this behavior
- * is unacceptable then use:
+ * is unacceptable, then use:
*
* lc = mnt_context_get_lock(cxt);
* if (lc)
@@ -1197,7 +1234,7 @@ struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
*
* mnt_context_set_options(cxt, "noexec,nosuid");
*
- * these both calls have the same effect.
+ * both of these calls have the same effect.
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1227,7 +1264,7 @@ int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
* @flags: returns MS_* mount flags
*
* Converts mount options string to MS_* flags and bitewise-OR the result with
- * already defined flags (see mnt_context_set_mflags()).
+ * the already defined flags (see mnt_context_set_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1268,7 +1305,7 @@ int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
*
* Sets userspace mount flags.
*
- * See also notest for mnt_context_set_mflags().
+ * See also notes for mnt_context_set_mflags().
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1287,7 +1324,7 @@ int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
* @flags: returns mount flags
*
* Converts mount options string to MNT_MS_* flags and bitewise-OR the result
- * with already defined flags (see mnt_context_set_user_mflags()).
+ * with the already defined flags (see mnt_context_set_user_mflags()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -1321,7 +1358,7 @@ int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags
* function allows to overwrite this behavior, and @data will be used instead
* of mount options.
*
- * The libmount does not deallocated the data by mnt_free_context(). Note that
+ * The libmount does not deallocate the data by mnt_free_context(). Note that
* NULL is also valid mount data.
*
* Returns: 0 on success, negative number in case of error.
@@ -1362,7 +1399,7 @@ int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
return mnt_fs_set_source(cxt->fs, "none");
/* ignore filesystems without source or filesystems
- * where the source is quasi-path (//foo/bar)
+ * where the source is a quasi-path (//foo/bar)
*/
if (!src || mnt_fs_is_netfs(cxt->fs))
return 0;
@@ -1504,8 +1541,8 @@ int mnt_context_prepare_target(struct libmnt_context *cxt)
}
/*
- * It's usully no error when we're not able to detect filesystem type -- we
- * will try to use types from /{etc,proc}/filesystems.
+ * It's usually no error when we're not able to detect the filesystem type -- we
+ * will try to use the types from /{etc,proc}/filesystems.
*/
int mnt_context_guess_fstype(struct libmnt_context *cxt)
{
@@ -1595,6 +1632,7 @@ int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
if (mnt_context_is_nohelpers(cxt)
|| !type
|| !strcmp(type, "none")
+ || strstr(type, "/..") /* don't try to smuggle path */
|| mnt_fs_is_swaparea(cxt->fs))
return 0;
@@ -1798,8 +1836,8 @@ static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
*
* mount /foo/bar
*
- * the path could be a mountpoint as well as source (for
- * example bind mount, symlink to device, ...).
+ * the path could be a mountpoint as well as a source (for
+ * example bind mount, symlink to a device, ...).
*/
if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
fs = mnt_table_find_target(tb, src, direction);
@@ -1869,7 +1907,7 @@ int mnt_context_apply_fstab(struct libmnt_context *cxt)
DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users!"));
cxt->optsmode = MNT_OMODE_USER;
} else if (cxt->optsmode == 0) {
- DBG(CXT, mnt_debug_h(cxt, "use default optmode"));
+ DBG(CXT, mnt_debug_h(cxt, "use default optsmode"));
cxt->optsmode = MNT_OMODE_AUTO;
} else if (cxt->optsmode & MNT_OMODE_NOTAB) {
cxt->optsmode &= ~MNT_OMODE_FSTAB;
@@ -1944,7 +1982,7 @@ int mnt_context_tab_applied(struct libmnt_context *cxt)
}
/*
- * This is not public function!
+ * This is not a public function!
*
* Returns 1 if *only propagation flags* change is requested.
*/
@@ -1974,7 +2012,7 @@ int mnt_context_propagation_only(struct libmnt_context *cxt)
* Global libmount status.
*
* The real exit code of the mount.type helper has to be tested by
- * mnt_context_get_helper_status(). The mnt_context_get_status() only inform
+ * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
* that exec() has been successful.
*
* Returns: 1 if mount.type or mount(2) syscall has been successfully called.
@@ -2046,7 +2084,7 @@ int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
*
* The @status should be 0 on success, or negative number on error (-errno).
*
- * This function should be used only if [u]mount(2) syscall is NOT called by
+ * This function should only be used if the [u]mount(2) syscall is NOT called by
* libmount code.
*
* Returns: 0 or negative number in case of error.
@@ -2086,11 +2124,11 @@ int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
* @action: MNT_ACT_{UMOUNT,MOUNT}
* @flags: not used now
*
- * This function infors libmount that used from [u]mount.type helper.
+ * This function informs libmount that used from [u]mount.type helper.
*
* The function also calls mnt_context_disable_helpers() to avoid recursive
* mount.type helpers calling. It you really want to call another
- * mount.type helper from your helper than you have to explicitly enable this
+ * mount.type helper from your helper, then you have to explicitly enable this
* feature by:
*
* mnt_context_disable_helpers(cxt, FALSE);
@@ -2120,7 +2158,7 @@ int mnt_context_init_helper(struct libmnt_context *cxt, int action,
* @c: getopt() result
* @arg: getopt() optarg
*
- * This function applies [u]mount.type command line option (for example parsed
+ * This function applies the [u]mount.type command line option (for example parsed
* by getopt or getopt_long) to @cxt. All unknown options are ignored and
* then 1 is returned.
*
@@ -2145,7 +2183,7 @@ int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
* @fs: filesystem
* @mounted: returns 1 for mounted and 0 for non-mounted filesystems
*
- * Please, read mnt_table_is_fs_mounted() description!
+ * Please, read the mnt_table_is_fs_mounted() description!
*
* Returns: 0 on success and negative number in case of error.
*/
@@ -2308,7 +2346,7 @@ int test_mount(struct libmnt_test *ts, int argc, char *argv[])
mnt_context_set_target(cxt, argv[idx++]);
}
- /* this is unnecessary! -- libmount is able to internaly
+ /* this is unnecessary! -- libmount is able to internally
* create and manage the lock
*/
lock = mnt_context_get_lock(cxt);
@@ -2317,7 +2355,7 @@ int test_mount(struct libmnt_test *ts, int argc, char *argv[])
rc = mnt_context_mount(cxt);
if (rc)
- printf("failed to mount: %m\n");
+ warn("failed to mount");
else
printf("successfully mounted\n");
diff --git a/libmount/src/context_loopdev.c b/libmount/src/context_loopdev.c
index 576b7f55a..44a7216b8 100644
--- a/libmount/src/context_loopdev.c
+++ b/libmount/src/context_loopdev.c
@@ -47,10 +47,10 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
/* Automatically create a loop device from a regular file if a
* filesystem is not specified or the filesystem is known for libblkid
* (these filesystems work with block devices only). The file size
- * should be at least 1KiB otherwise we will create empty loopdev where
- * is no mountable filesystem...
+ * should be at least 1KiB, otherwise we will create an empty loopdev with
+ * no mountable filesystem...
*
- * Note that there is not a restriction (on kernel side) that prevents regular
+ * Note that there is no restriction (on kernel side) that would prevent a regular
* file as a mount(2) source argument. A filesystem that is able to mount
* regular files could be implemented.
*/
@@ -73,7 +73,7 @@ int mnt_context_is_loopdev(struct libmnt_context *cxt)
}
-/* Check, if there already exists a mounted loop device on the mountpoint node
+/* Check if there already exists a mounted loop device on the mountpoint node
* with the same parameters.
*/
static int __attribute__((nonnull))
@@ -86,6 +86,8 @@ is_mounted_same_loopfile(struct libmnt_context *cxt,
struct libmnt_iter itr;
struct libmnt_fs *fs;
struct libmnt_cache *cache;
+ const char *bf;
+ int rc = 0;
assert(cxt);
assert(cxt->fs);
@@ -100,39 +102,36 @@ is_mounted_same_loopfile(struct libmnt_context *cxt,
cache = mnt_context_get_cache(cxt);
mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
- /* Search for mountpoint node in mtab, procceed if any of these has the
+ bf = cache ? mnt_resolve_path(backing_file, cache) : backing_file;
+
+ /* Search for a mountpoint node in mtab, proceed if any of these have the
* loop option set or the device is a loop device
*/
- while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ while (rc == 0 && mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *src = mnt_fs_get_source(fs);
const char *opts = mnt_fs_get_user_options(fs);
char *val;
size_t len;
- int res = 0;
if (!src || !mnt_fs_match_target(fs, target, cache))
continue;
+ rc = 0;
+
if (strncmp(src, "/dev/loop", 9) == 0) {
- res = loopdev_is_used((char *) src, backing_file,
- offset, LOOPDEV_FL_OFFSET);
+ rc = loopdev_is_used((char *) src, bf, offset, LOOPDEV_FL_OFFSET);
} else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {
val = strndup(val, len);
- res = loopdev_is_used((char *) val, backing_file,
- offset, LOOPDEV_FL_OFFSET);
+ rc = loopdev_is_used((char *) val, bf, offset, LOOPDEV_FL_OFFSET);
free(val);
}
-
- if (res) {
- DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
- return 1;
- }
}
-
- return 0;
+ if (rc)
+ DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
+ return rc;
}
int mnt_context_setup_loopdev(struct libmnt_context *cxt)
@@ -282,7 +281,7 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
if ((cxt->user_mountflags & MNT_MS_LOOP) &&
loopcxt_is_autoclear(&lc)) {
/*
- * autoclear flag accepted by kernel, don't store
+ * autoclear flag accepted by the kernel, don't store
* the "loop=" option to mtab.
*/
cxt->user_mountflags &= ~MNT_MS_LOOP;
@@ -298,7 +297,7 @@ int mnt_context_setup_loopdev(struct libmnt_context *cxt)
mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY);
/* we have to keep the device open until mount(1),
- * otherwise it will auto-cleared by kernel
+ * otherwise it will be auto-cleared by kernel
*/
cxt->loopdev_fd = loopcxt_get_fd(&lc);
loopcxt_set_fd(&lc, -1, 0);
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index d6691eb6a..89d1f4f29 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -21,6 +21,7 @@
#include "linux_version.h"
#include "mountP.h"
+#include "strutils.h"
/*
* Kernel supports only one MS_PROPAGATION flag change by one mount(2) syscall,
@@ -101,6 +102,30 @@ static int init_propagation(struct libmnt_context *cxt)
return 0;
}
+#if defined(HAVE_LIBSELINUX) || defined(HAVE_SMACK)
+struct libmnt_optname {
+ const char *name;
+ size_t namesz;
+};
+
+#define DEF_OPTNAME(n) { .name = n, .namesz = sizeof(n) - 1 }
+#define DEF_OPTNAME_LAST { .name = NULL }
+
+static int is_option(const char *name, size_t namesz,
+ const struct libmnt_optname *names)
+{
+ const struct libmnt_optname *p;
+
+ for (p = names; p && p->name; p++) {
+ if (p->namesz == namesz
+ && strncmp(name, p->name, namesz) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+#endif /* HAVE_LIBSELINUX || HAVE_SMACK */
+
/*
* this has to be called after mnt_context_evaluate_permissions()
*/
@@ -113,6 +138,25 @@ static int fix_optstr(struct libmnt_context *cxt)
struct libmnt_fs *fs;
#ifdef HAVE_LIBSELINUX
int se_fix = 0, se_rem = 0;
+ static const struct libmnt_optname selinux_options[] = {
+ DEF_OPTNAME("context"),
+ DEF_OPTNAME("fscontext"),
+ DEF_OPTNAME("defcontext"),
+ DEF_OPTNAME("rootcontext"),
+ DEF_OPTNAME("seclabel"),
+ DEF_OPTNAME_LAST
+ };
+#endif
+#ifdef HAVE_SMACK
+ int sm_rem = 0;
+ static const struct libmnt_optname smack_options[] = {
+ DEF_OPTNAME("smackfsdef"),
+ DEF_OPTNAME("smackfsfloor"),
+ DEF_OPTNAME("smackfshat"),
+ DEF_OPTNAME("smackfsroot"),
+ DEF_OPTNAME("smackfstransmute"),
+ DEF_OPTNAME_LAST
+ };
#endif
assert(cxt);
assert(cxt->fs);
@@ -129,8 +173,8 @@ static int fix_optstr(struct libmnt_context *cxt)
/*
* The "user" options is our business (so we can modify the option),
- * but exception is command line for /sbin/mount.<type> helpers. Let's
- * save the original user=<name> to call the helpers with unchanged
+ * the exception is command line for /sbin/mount.<type> helpers. Let's
+ * save the original user=<name> to call the helpers with an unchanged
* "user" setting.
*/
if (cxt->user_mountflags & MNT_MS_USER) {
@@ -168,7 +212,6 @@ static int fix_optstr(struct libmnt_context *cxt)
free(fs->user_optstr);
fs->user_optstr = NULL;
}
-
if (cxt->mountflags & MS_PROPAGATION) {
rc = init_propagation(cxt);
if (rc)
@@ -198,13 +241,15 @@ static int fix_optstr(struct libmnt_context *cxt)
if (!se_rem) {
/* de-duplicate SELinux options */
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "context");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "fscontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "defcontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "rootcontext");
- mnt_optstr_deduplicate_option(&fs->fs_optstr, "seclabel");
+ const struct libmnt_optname *p;
+ for (p = selinux_options; p && p->name; p++)
+ mnt_optstr_deduplicate_option(&fs->fs_optstr, p->name);
}
#endif
+#ifdef HAVE_SMACK
+ if (access("/sys/fs/smackfs", F_OK) != 0)
+ sm_rem = 1;
+#endif
while (!mnt_optstr_next_option(&next, &name, &namesz, &val, &valsz)) {
if (namesz == 3 && !strncmp(name, "uid", 3))
@@ -212,12 +257,9 @@ static int fix_optstr(struct libmnt_context *cxt)
else if (namesz == 3 && !strncmp(name, "gid", 3))
rc = mnt_optstr_fix_gid(&fs->fs_optstr, val, valsz, &next);
#ifdef HAVE_LIBSELINUX
- else if ((se_rem || se_fix) &&
- namesz >= 7 && (!strncmp(name, "context", 7) ||
- !strncmp(name, "fscontext", 9) ||
- !strncmp(name, "defcontext", 10) ||
- !strncmp(name, "rootcontext", 11) ||
- !strncmp(name, "seclabel", 8))) {
+ else if ((se_rem || se_fix)
+ && is_option(name, namesz, selinux_options)) {
+
if (se_rem) {
/* remove context= option */
next = name;
@@ -231,6 +273,15 @@ static int fix_optstr(struct libmnt_context *cxt)
val, valsz, &next);
}
#endif
+#ifdef HAVE_SMACK
+ else if (sm_rem && is_option(name, namesz, smack_options)) {
+
+ next = name;
+ rc = mnt_optstr_remove_option_at(&fs->fs_optstr,
+ name,
+ val ? val + valsz : name + namesz);
+ }
+#endif
if (rc)
goto done;
}
@@ -255,7 +306,7 @@ done:
}
/*
- * Converts already evaluated and fixed options to the form that is compatible
+ * Converts the already evaluated and fixed options to the form that is compatible
* with /sbin/mount.type helpers.
*/
static int generate_helper_optstr(struct libmnt_context *cxt, char **optstr)
@@ -278,13 +329,13 @@ static int generate_helper_optstr(struct libmnt_context *cxt, char **optstr)
if (cxt->user_mountflags & MNT_MS_USER) {
/*
* This is unnecessary for real user-mounts as mount.<type>
- * helpers have to always follow fstab rather than mount
- * options on command line.
+ * helpers always have to follow fstab rather than mount
+ * options on the command line.
*
- * But if you call mount.<type> as root then the helper follows
- * command line. If there is (for example) "user,exec" in fstab
+ * However, if you call mount.<type> as root, then the helper follows
+ * the command line. If there is (for example) "user,exec" in fstab,
* then we have to manually append the "exec" back to the options
- * string, bacause there is nothing like MS_EXEC (we have only
+ * string, bacause there is nothing like MS_EXEC (we only have
* MS_NOEXEC in mount flags and we don't care about the original
* mount string in libmount for VFS options).
*/
@@ -330,7 +381,7 @@ err:
/*
* this has to be called before fix_optstr()
*
- * Note that user=<name> maybe be used by some filesystems as filesystem
+ * Note that user=<name> may be used by some filesystems as a filesystem
* specific option (e.g. cifs). Yes, developers of such filesystems have
* allocated pretty hot place in hell...
*/
@@ -361,7 +412,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
/*
* user mount
*/
- if (!(cxt->flags & MNT_FL_TAB_APPLIED))
+ if (!mnt_context_tab_applied(cxt))
{
DBG(CXT, mnt_debug_h(cxt, "perms: fstab not applied, ignore user mount"));
return -EPERM;
@@ -433,7 +484,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
/*
* mnt_context_helper_setopt() backend
*
- * This function applies mount.type command line option (for example parsed
+ * This function applies the mount.type command line option (for example parsed
* by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
* then 1 is returned.
*
@@ -519,7 +570,7 @@ static int exec_helper(struct libmnt_context *cxt)
/*
* TODO: remove the exception for "nfs", -s is documented
- * for years should be usable everywhere.
+ * for years and should be usable everywhere.
*/
if (mnt_context_is_sloppy(cxt) &&
type && startswith(type, "nfs"))
@@ -651,7 +702,7 @@ static int do_mount(struct libmnt_context *cxt, const char *try_type)
return -EINVAL;
if (!src) {
/* unnecessary, should be already resolved in
- * mnt_context_prepare_srcpath(), but for sure... */
+ * mnt_context_prepare_srcpath(), but to be sure... */
DBG(CXT, mnt_debug_h(cxt, "WARNING: source is NULL -- using \"none\"!"));
src = "none";
}
@@ -831,10 +882,10 @@ int mnt_context_prepare_mount(struct libmnt_context *cxt)
* Call mount(2) or mount.type helper. Unnecessary for mnt_context_mount().
*
* Note that this function could be called only once. If you want to mount
- * another source or target than you have to call mnt_reset_context().
+ * another source or target, then you have to call mnt_reset_context().
*
- * If you want to call mount(2) for the same source and target with a different
- * mount flags or fstype then call mnt_context_reset_status() and then try
+ * If you want to call mount(2) for the same source and target with different
+ * mount flags or fstype, then call mnt_context_reset_status() and then try
* again mnt_context_do_mount().
*
* WARNING: non-zero return code does not mean that mount(2) syscall or
@@ -867,7 +918,7 @@ int mnt_context_do_mount(struct libmnt_context *cxt)
type = mnt_fs_get_fstype(cxt->fs);
if (type) {
if (strchr(type, ','))
- /* this only happens if fstab contains list of filesystems */
+ /* this only happens if fstab contains a list of filesystems */
res = do_mount_by_pattern(cxt, type);
else
res = do_mount(cxt, NULL);
@@ -935,7 +986,7 @@ int mnt_context_finalize_mount(struct libmnt_context *cxt)
* mnt_context_mount:
* @cxt: mount context
*
- * High-level, mounts filesystem by mount(2) or fork()+exec(/sbin/mount.type).
+ * High-level, mounts the filesystem by mount(2) or fork()+exec(/sbin/mount.type).
*
* This is similar to:
*
@@ -945,10 +996,10 @@ int mnt_context_finalize_mount(struct libmnt_context *cxt)
*
* See also mnt_context_disable_helpers().
*
- * Note that this function could be called only once. If you want to mount with
- * different setting than you have to call mnt_reset_context(). It's NOT enough
- * to call mnt_context_reset_status() if you want call this function more than
- * once, whole context has to be reseted.
+ * Note that this function should be called only once. If you want to mount with
+ * different settings, then you have to call mnt_reset_context(). It's NOT enough
+ * to call mnt_context_reset_status(). If you want to call this function more than
+ * once, the whole context has to be reset.
*
* WARNING: non-zero return code does not mean that mount(2) syscall or
* mount.type helper wasn't successfully called.
@@ -973,11 +1024,6 @@ int mnt_context_mount(struct libmnt_context *cxt)
rc = mnt_context_prepare_update(cxt);
if (!rc)
rc = mnt_context_do_mount(cxt);
-
- /* TODO: if mtab update is expected then check if the
- * target is really mounted read-write to avoid 'ro' in
- * mtab and 'rw' in /proc/mounts.
- */
if (!rc)
rc = mnt_context_update_tabs(cxt);
return rc;
@@ -989,7 +1035,7 @@ int mnt_context_mount(struct libmnt_context *cxt)
* @itr: iterator
* @fs: returns the current filesystem
* @mntrc: returns the return code from mnt_context_mount()
- * @ignored: returns 1 for not matching and 2 for already mounted filesystems
+ * @ignored: returns 1 for non-matching and 2 for already mounted filesystems
*
* This function tries to mount the next filesystem from fstab (as returned by
* mnt_context_get_fstab()). See also mnt_context_set_fstab().
@@ -1057,11 +1103,11 @@ int mnt_context_next_mount(struct libmnt_context *cxt,
/* ignore noauto filesystems */
(o && mnt_optstr_get_option(o, "noauto", NULL, NULL) == 0) ||
- /* ignore filesystems not match with options patterns */
+ /* ignore filesystems which don't match options patterns */
(cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
cxt->fstype_pattern)) ||
- /* ignore filesystems not match with type patterns */
+ /* ignore filesystems which don't match type patterns */
(cxt->optstr_pattern && !mnt_fs_match_options(*fs,
cxt->optstr_pattern))) {
if (ignored)
diff --git a/libmount/src/context_umount.c b/libmount/src/context_umount.c
index 4a8659c9c..dc16852c0 100644
--- a/libmount/src/context_umount.c
+++ b/libmount/src/context_umount.c
@@ -23,7 +23,7 @@
* umount2 flags
*/
#ifndef MNT_FORCE
-# define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
+# define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
#endif
#ifndef MNT_DETACH
@@ -39,8 +39,8 @@
#endif
/*
- * Called by mtab parser to filter out entries, nonzero means that
- * entry has to be filter out.
+ * Called by mtab parser to filter out entries, non-zero means that
+ * an entry has to be filtered out.
*/
static int mtab_filter(struct libmnt_fs *fs, void *data)
{
@@ -71,19 +71,25 @@ int mnt_context_find_umount_fs(struct libmnt_context *cxt,
struct libmnt_cache *cache = NULL;
char *cn_tgt = NULL, *loopdev = NULL;
+ if (pfs)
+ *pfs = NULL;
+
if (!cxt || !tgt || !pfs)
return -EINVAL;
DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS for '%s'", tgt));
+ if (!*tgt)
+ return 1; /* empty string is not an error */
+
/*
- * The mtab file maybe huge and on systems with utab we have to merge
+ * The mtab file may be huge and on systems with utab we have to merge
* userspace mount options into /proc/self/mountinfo. This all is
* expensive. The mtab filter allows to filter out entries, then
* mtab and utab are very tiny files.
*
* *but*... the filter uses mnt_fs_streq_{target,srcpath} functions
- * where LABEL, UUID or symlinks are to canonicalized. It means that
+ * where LABEL, UUID or symlinks are canonicalized. It means that
* it's usable only for canonicalized stuff (e.g. kernel mountinfo).
*/
if (!cxt->mtab_writable && *tgt == '/' &&
@@ -92,7 +98,7 @@ int mnt_context_find_umount_fs(struct libmnt_context *cxt,
struct stat st;
if (stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
- /* we'll canonicalized /proc/self/mountinfo */
+ /* we'll canonicalize /proc/self/mountinfo */
cache = mnt_context_get_cache(cxt);
cn_tgt = mnt_resolve_path(tgt, cache);
if (cn_tgt)
@@ -155,7 +161,10 @@ try_loopdev:
struct stat st;
if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
- int count = loopdev_count_by_backing_file(tgt, &loopdev);
+ int count;
+ const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt;
+
+ count = loopdev_count_by_backing_file(bf, &loopdev);
if (count == 1) {
DBG(CXT, mnt_debug_h(cxt,
"umount: %s --> %s (retry)", tgt, loopdev));
@@ -169,15 +178,21 @@ try_loopdev:
}
}
- *pfs = fs;
+ if (pfs)
+ *pfs = fs;
free(loopdev);
+ DBG(CXT, mnt_debug_h(cxt, "umount fs: %s", fs ? mnt_fs_get_target(fs) :
+ "<not found>"));
return fs ? 0 : 1;
err:
free(loopdev);
return rc;
}
+/* this is umount replacement to mnt_context_apply_fstab(), use
+ * mnt_context_tab_applied() to check result.
+ */
static int lookup_umount_fs(struct libmnt_context *cxt)
{
const char *tgt;
@@ -197,8 +212,8 @@ static int lookup_umount_fs(struct libmnt_context *cxt)
if (rc < 0)
return rc;
if (rc == 1 || !fs) {
- DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
- return 0;
+ DBG(CXT, mnt_debug_h(cxt, "umount: cannot find '%s' in mtab", tgt));
+ return 0; /* this is correct! */
}
if (fs != cxt->fs) {
@@ -237,7 +252,7 @@ static int is_associated_fs(const char *devname, struct libmnt_fs *fs)
if (!src)
return 0;
- /* check for offset option in @fs */
+ /* check for the offset option in @fs */
optstr = (char *) mnt_fs_get_user_options(fs);
if (optstr &&
@@ -300,7 +315,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
DBG(CXT, mnt_debug_h(cxt, "umount: evaluating permissions"));
- if (!(cxt->flags & MNT_FL_TAB_APPLIED)) {
+ if (!mnt_context_tab_applied(cxt)) {
DBG(CXT, mnt_debug_h(cxt,
"cannot find %s in mtab and you are not root",
mnt_fs_get_target(cxt->fs)));
@@ -317,7 +332,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
}
/*
- * User mounts has to be in /etc/fstab
+ * User mounts have to be in /etc/fstab
*/
rc = mnt_context_get_fstab(cxt, &fstab);
if (rc)
@@ -336,18 +351,20 @@ static int evaluate_permissions(struct libmnt_context *cxt)
* /dev/sda1 /mnt/zip auto user,noauto 0 0
* /dev/sda4 /mnt/zip auto user,noauto 0 0
* then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail.
- * So, we must not look for file, but for the pair (dev,file) in fstab.
+ * So, we must not look for the file, but for the pair (dev,file) in fstab.
*/
fs = mnt_table_find_pair(fstab, src, tgt, MNT_ITER_FORWARD);
if (!fs) {
/*
* It's possible that there is /path/file.img in fstab and
- * /dev/loop0 in mtab -- then we have to check releation
+ * /dev/loop0 in mtab -- then we have to check the relation
* between loopdev and the file.
*/
fs = mnt_table_find_target(fstab, tgt, MNT_ITER_FORWARD);
if (fs) {
- const char *dev = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */
+ struct libmnt_cache *cache = mnt_context_get_cache(cxt);
+ const char *sp = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */
+ const char *dev = sp && cache ? mnt_resolve_path(sp, cache) : sp;
if (!dev || !is_associated_fs(dev, fs))
fs = NULL;
@@ -384,7 +401,7 @@ static int evaluate_permissions(struct libmnt_context *cxt)
return 0;
}
/*
- * Check user=<username> setting from mtab if there is user, owner or
+ * Check user=<username> setting from mtab if there is a user, owner or
* group option in /etc/fstab
*/
if (u_flags & (MNT_MS_USER | MNT_MS_OWNER | MNT_MS_GROUP)) {
@@ -409,6 +426,8 @@ static int evaluate_permissions(struct libmnt_context *cxt)
if (optstr && !mnt_optstr_get_option(optstr,
"user", &mtab_user, &sz) && sz)
ok = !strncmp(curr_user, mtab_user, sz);
+
+ free(curr_user);
}
if (ok) {
@@ -539,7 +558,7 @@ int mnt_context_umount_setopt(struct libmnt_context *cxt, int c, char *arg)
return rc;
}
-/* Check whether the kernel supports UMOUNT_NOFOLLOW flag */
+/* Check whether the kernel supports the UMOUNT_NOFOLLOW flag */
static int umount_nofollow_support(void)
{
int res = umount2("", UMOUNT_UNUSED);
@@ -860,7 +879,7 @@ int mnt_context_umount(struct libmnt_context *cxt)
* mnt_context_set_options_pattern() to simulate umount -a -O pattern
* mnt_context_set_fstype_pattern() to simulate umount -a -t pattern
*
- * If the filesystem is not mounted or does not match defined criteria,
+ * If the filesystem is not mounted or does not match the defined criteria,
* then the function mnt_context_next_umount() returns zero, but the @ignored is
* non-zero. Note that the root filesystem is always ignored.
*
@@ -909,11 +928,11 @@ int mnt_context_next_umount(struct libmnt_context *cxt,
DBG(CXT, mnt_debug_h(cxt, "next-umount: trying %s", tgt));
- /* ignore filesystems not match with options patterns */
+ /* ignore filesystems which don't match options patterns */
if ((cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
cxt->fstype_pattern)) ||
- /* ignore filesystems not match with type patterns */
+ /* ignore filesystems which don't match type patterns */
(cxt->optstr_pattern && !mnt_fs_match_options(*fs,
cxt->optstr_pattern))) {
if (ignored)
diff --git a/libmount/src/fs.c b/libmount/src/fs.c
index c95cdc7e7..3ab614503 100644
--- a/libmount/src/fs.c
+++ b/libmount/src/fs.c
@@ -21,6 +21,9 @@
/**
* mnt_new_fs:
*
+ * The initial refcount is 1, and needs to be decremented to
+ * release the resources of the filesystem.
+ *
* Returns: newly allocated struct libmnt_fs.
*/
struct libmnt_fs *mnt_new_fs(void)
@@ -29,8 +32,9 @@ struct libmnt_fs *mnt_new_fs(void)
if (!fs)
return NULL;
- /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
+ fs->refcount = 1;
INIT_LIST_HEAD(&fs->ents);
+ /*DBG(FS, mnt_debug_h(fs, "alloc"));*/
return fs;
}
@@ -38,7 +42,10 @@ struct libmnt_fs *mnt_new_fs(void)
* mnt_free_fs:
* @fs: fs pointer
*
- * Deallocates the fs.
+ * Deallocates the fs. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_fs().
+ *
+ * The reference counting is supported since util-linux v2.24.
*/
void mnt_free_fs(struct libmnt_fs *fs)
{
@@ -47,6 +54,7 @@ void mnt_free_fs(struct libmnt_fs *fs)
list_del(&fs->ents);
/*DBG(FS, mnt_debug_h(fs, "free"));*/
+ WARN_REFCOUNT(FS, fs, fs->refcount);
free(fs->source);
free(fs->bindsrc);
@@ -62,6 +70,7 @@ void mnt_free_fs(struct libmnt_fs *fs)
free(fs->user_optstr);
free(fs->attrs);
free(fs->opt_fields);
+ free(fs->comment);
free(fs);
}
@@ -74,8 +83,46 @@ void mnt_free_fs(struct libmnt_fs *fs)
*/
void mnt_reset_fs(struct libmnt_fs *fs)
{
- if (fs)
- memset(fs, 0, sizeof(*fs));
+ int ref;
+
+ if (!fs)
+ return;
+
+ ref = fs->refcount;
+ memset(fs, 0, sizeof(*fs));
+ INIT_LIST_HEAD(&fs->ents);
+ fs->refcount = ref;
+}
+
+/**
+ * mnt_ref_fs:
+ * @fs: fs pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_fs(struct libmnt_fs *fs)
+{
+ if (fs) {
+ fs->refcount++;
+ /*DBG(FS, mnt_debug_h(fs, "ref=%d", fs->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_fs:
+ * @fs: fs pointer
+ *
+ * De-increments reference counter, on zero the @fs is automatically
+ * deallocated by mnt_free_fs().
+ */
+void mnt_unref_fs(struct libmnt_fs *fs)
+{
+ if (fs) {
+ fs->refcount--;
+ /*DBG(FS, mnt_debug_h(fs, "unref=%d", fs->refcount));*/
+ if (fs->refcount <= 0)
+ mnt_free_fs(fs);
+ }
}
static inline int update_str(char **dest, const char *src)
@@ -106,7 +153,7 @@ static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
char **n = (char **) (new + offset);
if (*n)
- return 0; /* already set, not overwrite */
+ return 0; /* already set, don't overwrite */
return update_str(n, *o);
}
@@ -117,7 +164,7 @@ static inline int cpy_str_at_offset(void *new, const void *old, size_t offset)
* @src: source FS
*
* If @dest is NULL, then a new FS is allocated, if any @dest field is already
- * set then the field is NOT overwrited.
+ * set, then the field is NOT overwritten.
*
* This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is
* not linked with any existing mnt_tab.
@@ -250,7 +297,12 @@ err:
void *mnt_fs_get_userdata(struct libmnt_fs *fs)
{
assert(fs);
- return fs ? fs->userdata : NULL;
+
+ if (!fs)
+ return NULL;
+
+ /*DBG(FS, mnt_debug_h(fs, "get userdata [%p]", fs->userdata));*/
+ return fs->userdata;
}
/**
@@ -267,6 +319,8 @@ int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data)
assert(fs);
if (!fs)
return -EINVAL;
+
+ /*DBG(FS, mnt_debug_h(fs, "set userdata [%p]", fs->userdata));*/
fs->userdata = data;
return 0;
}
@@ -310,7 +364,7 @@ const char *mnt_fs_get_source(struct libmnt_fs *fs)
}
/*
- * Used by parser ONLY (@source has to be freed on error)
+ * Used by the parser ONLY (@source has to be freed on error)
*/
int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
{
@@ -318,9 +372,12 @@ int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source)
assert(fs);
- if (source && *source != '/' && strchr(source, '=')) {
- if (blkid_parse_tag_string(source, &t, &v) != 0)
- return -1;
+ if (source && blkid_parse_tag_string(source, &t, &v) == 0 &&
+ !mnt_valid_tagname(t)) {
+ /* parsable but unknown tag -- ignore */
+ free(t);
+ free(v);
+ t = v = NULL;
}
if (fs->source != source)
@@ -370,7 +427,7 @@ int mnt_fs_set_source(struct libmnt_fs *fs, const char *source)
* @fs: fs
* @path: source path
*
- * Compares @fs source path with @path. The tailing slash is ignored.
+ * Compares @fs source path with @path. The trailing slash is ignored.
* See also mnt_fs_match_source().
*
* Returns: 1 if @fs source path equal to @path, otherwise 0.
@@ -399,7 +456,7 @@ int mnt_fs_streq_srcpath(struct libmnt_fs *fs, const char *path)
* @fs: fs
* @path: mount point
*
- * Compares @fs target path with @path. The tailing slash is ignored.
+ * Compares @fs target path with @path. The trailing slash is ignored.
* See also mnt_fs_match_target().
*
* Returns: 1 if @fs target path equal to @path, otherwise 0.
@@ -418,8 +475,8 @@ int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
*
* "TAG" is NAME=VALUE (e.g. LABEL=foo)
*
- * The TAG is the first column in the fstab file. The TAG or "srcpath" has to
- * be always set for all entries.
+ * The TAG is the first column in the fstab file. The TAG or "srcpath" always has
+ * to be set for all entries.
*
* See also mnt_fs_get_source().
*
@@ -441,7 +498,7 @@ int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path)
* </programlisting>
* </informalexample>
*
- * Returns: 0 on success or negative number in case that a TAG is not defined.
+ * Returns: 0 on success or negative number in case a TAG is not defined.
*/
int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value)
{
@@ -502,10 +559,10 @@ static int mnt_fs_get_flags(struct libmnt_fs *fs)
/**
* mnt_fs_get_propagation:
* @fs: mountinfo entry
- * @flags: returns propagation MS_* flags as present in mountinfo file
+ * @flags: returns propagation MS_* flags as present in the mountinfo file
*
- * Note that this function set @flags to zero if not found any propagation flag
- * in mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
+ * Note that this function sets @flags to zero if no propagation flags are found
+ * in the mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored
* in the mountinfo file.
*
* Returns: 0 on success or negative number in case of error.
@@ -594,7 +651,7 @@ const char *mnt_fs_get_fstype(struct libmnt_fs *fs)
return fs ? fs->fstype : NULL;
}
-/* Used by struct libmnt_file parser only */
+/* Used by the struct libmnt_file parser only */
int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype)
{
assert(fs);
@@ -670,7 +727,7 @@ static char *merge_optstr(const char *vfs, const char *fs)
if (!strcmp(vfs, fs))
return strdup(vfs); /* e.g. "aaa" and "aaa" */
- /* leave space for leading "r[ow],", "," and trailing zero */
+ /* leave space for the leading "r[ow],", "," and the trailing zero */
sz = strlen(vfs) + strlen(fs) + 5;
res = malloc(sz);
if (!res)
@@ -701,7 +758,7 @@ static char *merge_optstr(const char *vfs, const char *fs)
* mnt_fs_strdup_options:
* @fs: fstab/mtab/mountinfo entry pointer
*
- * Merges all mount options (VFS, FS and userspace) to the one options string
+ * Merges all mount options (VFS, FS and userspace) to one options string
* and returns the result. This function does not modigy @fs.
*
* Returns: pointer to string (can be freed by free(3)) or NULL in case of error.
@@ -757,10 +814,10 @@ const char *mnt_fs_get_optional_fields(struct libmnt_fs *fs)
* @fs: fstab/mtab/mountinfo entry pointer
* @optstr: options string
*
- * Splits @optstr to VFS, FS and userspace mount options and update relevat
+ * Splits @optstr to VFS, FS and userspace mount options and updates relevant
* parts of @fs.
*
- * Returns: 0 on success, or negative number icase of error.
+ * Returns: 0 on success, or negative number in case of error.
*/
int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
{
@@ -774,8 +831,12 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
if (rc)
return rc;
n = strdup(optstr);
- if (!n)
+ if (!n) {
+ free(u);
+ free(v);
+ free(f);
return -ENOMEM;
+ }
}
free(fs->fs_optstr);
@@ -799,7 +860,7 @@ int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr)
* Parses (splits) @optstr and appends results to VFS, FS and userspace lists
* of options.
*
- * If @optstr is NULL then @fs is not modified and 0 is returned.
+ * If @optstr is NULL, then @fs is not modified and 0 is returned.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -815,6 +876,9 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
return 0;
rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
+ if (rc)
+ return rc;
+
if (!rc && v)
rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL);
if (!rc && f)
@@ -836,10 +900,10 @@ int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr)
* @fs: fstab/mtab/mountinfo entry
* @optstr: mount options
*
- * Parses (splits) @optstr and prepands results to VFS, FS and userspace lists
+ * Parses (splits) @optstr and prepends the results to VFS, FS and userspace lists
* of options.
*
- * If @optstr is NULL then @fs is not modified and 0 is returned.
+ * If @optstr is NULL, then @fs is not modified and 0 is returned.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -855,6 +919,9 @@ int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr)
return 0;
rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0);
+ if (rc)
+ return rc;
+
if (!rc && v)
rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL);
if (!rc && f)
@@ -925,10 +992,10 @@ const char *mnt_fs_get_attributes(struct libmnt_fs *fs)
* @optstr: options string
*
* Sets mount attributes. The attributes are mount(2) and mount(8) independent
- * options, these options are not send to kernel and are not interpreted by
+ * options, these options are not sent to the kernel and are not interpreted by
* libmount. The attributes are stored in /run/mount/utab only.
*
- * The atrtributes are managed by libmount in userspace only. It's possible
+ * The attributes are managed by libmount in userspace only. It's possible
* that information stored in userspace will not be available for libmount
* after CLONE_FS unshare. Be careful, and don't use attributes if possible.
*
@@ -1221,7 +1288,7 @@ dev_t mnt_fs_get_devno(struct libmnt_fs *fs)
* mnt_fs_get_tid:
* @fs: /proc/tid/mountinfo entry
*
- * Returns: TID (task ID) for filesystems read from mountinfo file
+ * Returns: TID (task ID) for filesystems read from the mountinfo file
*/
pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
{
@@ -1233,10 +1300,10 @@ pid_t mnt_fs_get_tid(struct libmnt_fs *fs)
* mnt_fs_get_option:
* @fs: fstab/mtab/mountinfo entry pointer
* @name: option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of options value or 0
*
- * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ * Returns: 0 on success, 1 when @name not found or negative number in case of error.
*/
int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
char **value, size_t *valsz)
@@ -1259,10 +1326,10 @@ int mnt_fs_get_option(struct libmnt_fs *fs, const char *name,
* mnt_fs_get_attribute:
* @fs: fstab/mtab/mountinfo entry pointer
* @name: option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of options value or 0
*
- * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ * Returns: 0 on success, 1 when @name not found or negative number in case of error.
*/
int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
char **value, size_t *valsz)
@@ -1278,6 +1345,67 @@ int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
}
/**
+ * mnt_fs_get_comment:
+ * @fs: fstab/mtab/mountinfo entry pointer
+ *
+ * Returns: 0 on success, 1 when not found the @name or negative number in case of error.
+ */
+const char *mnt_fs_get_comment(struct libmnt_fs *fs)
+{
+ assert(fs);
+ if (!fs)
+ return NULL;
+ return fs->comment;
+}
+
+/**
+ * mnt_fs_set_comment:
+ * @fs: fstab entry pointer
+ * @comm: comment string
+ *
+ * Note that the comment has to be terminated by '\n' (new line), otherwise
+ * the whole filesystem entry will be written as a comment to the tabfile (e.g.
+ * fstab).
+ *
+ * Returns: 0 on success or <0 in case of error.
+ */
+int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm)
+{
+ char *p = NULL;
+
+ assert(fs);
+ if (!fs)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+
+ free(fs->comment);
+ fs->comment = p;
+ return 0;
+}
+
+/**
+ * mnt_fs_append_comment:
+ * @fs: fstab entry pointer
+ * @comm: comment string
+ *
+ * See also mnt_fs_set_comment().
+ *
+ * Returns: 0 on success or <0 in case of error.
+ */
+int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm)
+{
+ assert(fs);
+ if (!fs)
+ return -EINVAL;
+
+ return append_string(&fs->comment, comm);
+}
+
+/**
* mnt_fs_match_target:
* @fs: filesystem
* @target: mountpoint path
@@ -1291,7 +1419,7 @@ int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name,
*
* The 2nd and 3rd attempts are not performed when @cache is NULL.
*
- * Returns: 1 if @fs target is equal to @target else 0.
+ * Returns: 1 if @fs target is equal to @target, else 0.
*/
int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
struct libmnt_cache *cache)
@@ -1326,7 +1454,7 @@ int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
* @source: tag or path (device or so) or NULL
* @cache: tags/paths cache or NULL
*
- * Possible are four attempts:
+ * Four attempts are possible:
* 1) compare @source with @fs->source
* 2) compare realpath(@source) with @fs->source
* 3) compare realpath(@source) with realpath(@fs->source)
@@ -1335,7 +1463,7 @@ int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
* The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
* 2nd and 3rd attempts are not performed if @fs->source is tag.
*
- * Returns: 1 if @fs source is equal to @source else 0.
+ * Returns: 1 if @fs source is equal to @source, else 0.
*/
int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
struct libmnt_cache *cache)
@@ -1379,14 +1507,14 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
return 1;
}
if (src || mnt_fs_get_tag(fs, &t, &v))
- /* src path does not match and tag is not defined */
+ /* src path does not match and the tag is not defined */
return 0;
/* read @source's tags to the cache */
if (mnt_cache_read_tags(cache, cn) < 0) {
if (errno == EACCES) {
/* we don't have permissions to read TAGs from
- * @source, but can translate @fs tag to devname.
+ * @source, but can translate the @fs tag to devname.
*
* (because libblkid uses udev symlinks and this is
* accessible for non-root uses)
@@ -1398,7 +1526,7 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
return 0;
}
- /* 4) has the @source a tag that matches with tag from @fs ? */
+ /* 4) has the @source a tag that matches with the tag from @fs ? */
if (mnt_cache_device_has_tag(cache, cn, t, v))
return 1;
@@ -1412,7 +1540,7 @@ int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
*
* For more details see mnt_match_fstype().
*
- * Returns: 1 if @fs type is matching to @types else 0. The function returns
+ * Returns: 1 if @fs type is matching to @types, else 0. The function returns
* 0 when types is NULL.
*/
int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
@@ -1428,7 +1556,7 @@ int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types)
*
* For more details see mnt_match_options().
*
- * Returns: 1 if @fs type is matching to @options else 0. The function returns
+ * Returns: 1 if @fs type is matching to @options, else 0. The function returns
* 0 when types is NULL.
*/
int mnt_fs_match_options(struct libmnt_fs *fs, const char *options)
@@ -1493,6 +1621,8 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
minor(mnt_fs_get_devno(fs)));
if (mnt_fs_get_tid(fs))
fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs));
+ if (mnt_fs_get_comment(fs))
+ fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs));
return 0;
}
@@ -1501,7 +1631,7 @@ int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file)
* mnt_free_mntent:
* @mnt: mount entry
*
- * Deallocates "mntent.h" mount entry.
+ * Deallocates the "mntent.h" mount entry.
*/
void mnt_free_mntent(struct mntent *mnt)
{
@@ -1519,11 +1649,11 @@ void mnt_free_mntent(struct mntent *mnt)
* @fs: filesystem
* @mnt: mount description (as described in mntent.h)
*
- * Copies information from @fs to struct mntent @mnt. If @mnt is already set
+ * Copies the information from @fs to struct mntent @mnt. If @mnt is already set,
* then the struct mntent items are reallocated and updated. See also
* mnt_free_mntent().
*
- * Returns: 0 on success and negative number in case of error.
+ * Returns: 0 on success and a negative number in case of error.
*/
int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt)
{
diff --git a/libmount/src/init.c b/libmount/src/init.c
index 4e5f489c4..a14637d75 100644
--- a/libmount/src/init.c
+++ b/libmount/src/init.c
@@ -8,7 +8,7 @@
/**
* SECTION: init
* @title: Library initialization
- * @short_description: initialize debuging
+ * @short_description: initialize debugging
*/
#include <stdarg.h>
@@ -19,13 +19,13 @@ int libmount_debug_mask;
/**
* mnt_init_debug:
- * @mask: debug mask (0xffff to enable full debuging)
+ * @mask: debug mask (0xffff to enable full debugging)
*
- * If the @mask is not specified then this function reads
- * LIBMOUNT_DEBUG environment variable to get the mask.
+ * If the @mask is not specified, then this function reads
+ * the LIBMOUNT_DEBUG environment variable to get the mask.
*
- * Already initialized debugging stuff cannot be changed. It does not
- * have effect to call this function twice.
+ * Already initialized debugging stuff cannot be changed. Calling
+ * this function twice has no effect.
*/
void mnt_init_debug(int mask)
{
@@ -40,7 +40,7 @@ void mnt_init_debug(int mask)
libmount_debug_mask |= MNT_DEBUG_INIT;
- if (libmount_debug_mask && libmount_debug_mask != MNT_DEBUG_INIT) {
+ if (libmount_debug_mask != MNT_DEBUG_INIT) {
const char *ver = NULL;
const char **features = NULL, **p;
diff --git a/libmount/src/iter.c b/libmount/src/iter.c
index d7b8adbef..016f88e35 100644
--- a/libmount/src/iter.c
+++ b/libmount/src/iter.c
@@ -10,8 +10,8 @@
* @title: Iterator
* @short_description: unified iterator
*
- * The iterator keeps direction and last position for access to the internal
- * library tables/lists.
+ * The iterator keeps the direction and the last position
+ * for access to the internal library tables/lists.
*/
#include <stdio.h>
#include <string.h>
@@ -38,7 +38,7 @@ struct libmnt_iter *mnt_new_iter(int direction)
* mnt_free_iter:
* @itr: iterator pointer
*
- * Deallocates iterator.
+ * Deallocates the iterator.
*/
void mnt_free_iter(struct libmnt_iter *itr)
{
@@ -48,9 +48,9 @@ void mnt_free_iter(struct libmnt_iter *itr)
/**
* mnt_reset_iter:
* @itr: iterator pointer
- * @direction: MNT_INTER_{FOR,BACK}WARD or -1 to keep the derection unchanged
+ * @direction: MNT_INTER_{FOR,BACK}WARD or -1 to keep the direction unchanged
*
- * Resets iterator.
+ * Resets the iterator.
*/
void mnt_reset_iter(struct libmnt_iter *itr, int direction)
{
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index db479e186..8c8e739c9 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -41,7 +41,7 @@ struct libmnt_cache;
/**
* libmnt_lock:
*
- * Stores information about locked file (e.g. /etc/mtab)
+ * Stores information about the locked file (e.g. /etc/mtab)
*/
struct libmnt_lock;
@@ -197,6 +197,7 @@ extern char *mnt_mangle(const char *str)
extern char *mnt_unmangle(const char *str)
__ul_attribute__((warn_unused_result));
+extern int mnt_tag_is_valid(const char *tag);
extern int mnt_fstype_is_netfs(const char *type);
extern int mnt_fstype_is_pseudofs(const char *type);
@@ -216,6 +217,9 @@ extern struct libmnt_cache *mnt_new_cache(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_cache(struct libmnt_cache *cache);
+extern void mnt_ref_cache(struct libmnt_cache *cache);
+extern void mnt_unref_cache(struct libmnt_cache *cache);
+
extern int mnt_cache_read_tags(struct libmnt_cache *cache, const char *devname);
extern int mnt_cache_device_has_tag(struct libmnt_cache *cache,
@@ -302,6 +306,8 @@ extern int mnt_lock_block_signals(struct libmnt_lock *ml, int enable);
extern struct libmnt_fs *mnt_new_fs(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_fs(struct libmnt_fs *fs);
+extern void mnt_ref_fs(struct libmnt_fs *fs);
+extern void mnt_unref_fs(struct libmnt_fs *fs);
extern void mnt_reset_fs(struct libmnt_fs *fs);
extern struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest,
@@ -369,6 +375,10 @@ extern off_t mnt_fs_get_size(struct libmnt_fs *fs);
extern off_t mnt_fs_get_usedsize(struct libmnt_fs *fs);
extern int mnt_fs_get_priority(struct libmnt_fs *fs);
+extern const char *mnt_fs_get_comment(struct libmnt_fs *fs);
+extern int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm);
+extern int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm);
+
extern int mnt_fs_match_target(struct libmnt_fs *fs, const char *target,
struct libmnt_cache *cache);
extern int mnt_fs_match_source(struct libmnt_fs *fs, const char *source,
@@ -406,12 +416,31 @@ extern struct libmnt_table *mnt_new_table(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_table(struct libmnt_table *tb);
+extern void mnt_ref_table(struct libmnt_table *tb);
+extern void mnt_unref_table(struct libmnt_table *tb);
+
extern int mnt_reset_table(struct libmnt_table *tb);
extern int mnt_table_get_nents(struct libmnt_table *tb);
+extern int mnt_table_is_empty(struct libmnt_table *tb);
+
+extern int mnt_table_set_userdata(struct libmnt_table *tb, void *data);
+extern void *mnt_table_get_userdata(struct libmnt_table *tb);
+
+extern void mnt_table_enable_comments(struct libmnt_table *tb, int enable);
+extern int mnt_table_with_comments(struct libmnt_table *tb);
+extern const char *mnt_table_get_intro_comment(struct libmnt_table *tb);
+extern int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm);
+extern int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm);
+extern int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm);
+extern const char *mnt_table_get_trailing_comment(struct libmnt_table *tb);
+extern int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm);
+
extern int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc);
extern struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb);
extern int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs);
extern int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs);
+extern int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs);
+extern int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs);
extern int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs **fs);
extern int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
@@ -449,6 +478,9 @@ extern struct libmnt_update *mnt_new_update(void)
__ul_attribute__((warn_unused_result));
extern void mnt_free_update(struct libmnt_update *upd);
+extern int mnt_table_replace_file(struct libmnt_table *tb, const char *filename);
+extern int mnt_table_write_file(struct libmnt_table *tb, FILE *file);
+
extern int mnt_update_is_ready(struct libmnt_update *upd);
extern int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
const char *target, struct libmnt_fs *fs);
@@ -578,6 +610,10 @@ extern const char *mnt_context_get_source(struct libmnt_context *cxt);
extern const char *mnt_context_get_target(struct libmnt_context *cxt);
extern const char *mnt_context_get_fstype(struct libmnt_context *cxt);
+extern void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt);
+extern void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt);
+extern void *mnt_context_get_fs_userdata(struct libmnt_context *cxt);
+
extern int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr);
extern int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr);
@@ -715,10 +751,10 @@ extern int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status
#define MS_NODIRATIME 0x800 /* 2048: Don't update directory access times */
#endif
#ifndef MS_BIND
-#define MS_BIND 0x1000 /* 4096: Mount existing tree also elsewhere */
+#define MS_BIND 0x1000 /* 4096: Mount existing tree elsewhere as well */
#endif
#ifndef MS_MOVE
-#define MS_MOVE 0x2000 /* 8192: Atomically move tree */
+#define MS_MOVE 0x2000 /* 8192: Atomically move the tree */
#endif
#ifndef MS_REC
#define MS_REC 0x4000 /* 16384: Recursive loopback */
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index 2ea483989..d1180d35b 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -256,3 +256,38 @@ global:
mnt_context_find_umount_fs;
mnt_table_find_mountpoint;
} MOUNT_2.22;
+
+MOUNT_2.24 {
+global:
+ mnt_context_get_fstab_userdata;
+ mnt_context_get_fs_userdata;
+ mnt_context_get_mtab_userdata;
+ mnt_fs_append_comment;
+ mnt_fs_get_comment;
+ mnt_fs_set_comment;
+ mnt_ref_cache;
+ mnt_ref_fs;
+ mnt_ref_table;
+ mnt_table_append_intro_comment;
+ mnt_table_append_trailing_comment;
+ mnt_table_enable_comments;
+ mnt_table_first_fs;
+ mnt_table_get_intro_comment;
+ mnt_table_get_trailing_comment;
+ mnt_table_get_userdata;
+ mnt_table_is_empty;
+ mnt_table_last_fs;
+ mnt_table_replace_file;
+ mnt_table_set_intro_comment;
+ mnt_table_set_trailing_comment;
+ mnt_table_set_userdata;
+ mnt_table_with_comments;
+ mnt_table_write_file;
+ mnt_unref_cache;
+ mnt_unref_fs;
+ mnt_unref_table;
+} MOUNT_2.23;
+
+MOUNT_2.25 {
+ mnt_tag_is_valid;
+} MOUNT_2.24;
diff --git a/libmount/src/lock.c b/libmount/src/lock.c
index e73edf54b..d9b6f5939 100644
--- a/libmount/src/lock.c
+++ b/libmount/src/lock.c
@@ -10,9 +10,9 @@
* @title: Locking
* @short_description: locking methods for /etc/mtab or another libmount files
*
- * The mtab lock is backwardly compatible with the standard linux /etc/mtab
+ * The mtab lock is backwards compatible with the standard linux /etc/mtab
* locking. Note, it's necessary to use the same locking schema in all
- * application that access the file.
+ * applications that access the file.
*/
#include <sys/time.h>
#include <time.h>
@@ -21,6 +21,8 @@
#include <limits.h>
#include <sys/file.h>
+#include "strutils.h"
+#include "closestream.h"
#include "pathnames.h"
#include "mountP.h"
@@ -246,7 +248,7 @@ static void mnt_lockalrm_handler(int sig __attribute__((__unused__)))
/*
* Waits for F_SETLKW, unfortunately we have to use SIGALRM here to interrupt
- * fcntl() to avoid never ending waiting.
+ * fcntl() to avoid neverending waiting.
*
* Returns: 0 on success, 1 on timeout, -errno on error.
*/
@@ -292,7 +294,7 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* soon as the lock file is deleted by the first mount, and immediately
* afterwards a third mount comes, creates a new /etc/mtab~, applies
* flock to that, and also proceeds, so that the second and third mount
- * now both are scribbling in /etc/mtab.
+ * are now both scribbling in /etc/mtab.
*
* The new code uses a link() instead of a creat(), where we proceed
* only if it was us that created the lock, and hence we always have
@@ -307,13 +309,13 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* The original mount locking code has used sleep(1) between attempts and
* maximal number of attempts has been 5.
*
- * There was very small number of attempts and extremely long waiting (1s)
+ * There was a very small number of attempts and extremely long waiting (1s)
* that is useless on machines with large number of mount processes.
*
- * Now we wait few thousand microseconds between attempts and we have a global
- * time limit (30s) rather than limit for number of attempts. The advantage
+ * Now we wait for a few thousand microseconds between attempts and we have a global
+ * time limit (30s) rather than a limit for the number of attempts. The advantage
* is that this method also counts time which we spend in fcntl(F_SETLKW) and
- * number of attempts is not restricted.
+ * the number of attempts is not restricted.
* -- kzak@redhat.com [Mar-2007]
*
*
@@ -326,7 +328,7 @@ static int mnt_wait_mtab_lock(struct libmnt_lock *ml, struct flock *fl, time_t m
* -- kzak@redhat.com [May-2009]
*/
-/* maximum seconds between first and last attempt */
+/* maximum seconds between the first and the last attempt */
#define MOUNTLOCK_MAXTIME 30
/* sleep time (in microseconds, max=999999) between attempts */
@@ -339,9 +341,9 @@ static void unlock_mtab(struct libmnt_lock *ml)
if (!ml->locked && ml->lockfile && ml->linkfile)
{
- /* We have (probably) all files, but we don't own the lock,
+ /* We (probably) have all the files, but we don't own the lock,
* Really? Check it! Maybe ml->locked wasn't set properly
- * because code was interrupted by signal. Paranoia? Yes.
+ * because the code was interrupted by a signal. Paranoia? Yes.
*
* We own the lock when linkfile == lockfile.
*/
@@ -491,10 +493,10 @@ failed:
* mnt_lock_file
* @ml: pointer to struct libmnt_lock instance
*
- * Creates lock file (e.g. /etc/mtab~). Note that this function may
+ * Creates a lock file (e.g. /etc/mtab~). Note that this function may
* use alarm().
*
- * Your application has to always call mnt_unlock_file() before exit.
+ * Your application always has to call mnt_unlock_file() before exit.
*
* Traditional mtab locking scheme:
*
@@ -521,7 +523,7 @@ int mnt_lock_file(struct libmnt_lock *ml)
* mnt_unlock_file:
* @ml: lock struct
*
- * Unlocks the file. The function could be called independently on the
+ * Unlocks the file. The function could be called independently of the
* lock status (for example from exit(3)).
*/
void mnt_unlock_file(struct libmnt_lock *ml)
@@ -573,7 +575,9 @@ void increment_data(const char *filename, int verbose, int loopno)
err(EXIT_FAILURE, "%d: failed to open: %s", getpid(), filename);
fprintf(f, "%ld", num);
- fclose(f);
+
+ if (close_stream(f) != 0)
+ err(EXIT_FAILURE, "write failed: %s", filename);
if (verbose)
fprintf(stderr, "%d: %s: %ld --> %ld (loop=%d)\n", getpid(),
@@ -667,7 +671,7 @@ int test_lock(struct libmnt_test *ts, int argc, char *argv[])
mnt_free_lock(lock);
lock = NULL;
- /* The mount command usually finish after mtab update. We
+ /* The mount command usually finishes after a mtab update. We
* simulate this via short sleep -- it's also enough to make
* concurrent processes happy.
*/
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index e064a6849..9362c0042 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -55,6 +55,13 @@
# include <stdio.h>
# include <stdarg.h>
+# define WARN_REFCOUNT(m, o, r) \
+ do { \
+ if ((MNT_DEBUG_ ## m) & libmount_debug_mask && r != 0) \
+ fprintf(stderr, "%d: libmount: %8s: [%p]: *** deallocates with refcount=%d\n", \
+ getpid(), # m, o, r); \
+ } while (0)
+
# define ON_DBG(m, x) do { \
if ((MNT_DEBUG_ ## m) & libmount_debug_mask) { \
x; \
@@ -100,6 +107,7 @@ mnt_debug_h(void *handler, const char *mesg, ...)
}
#else /* !CONFIG_LIBMOUNT_DEBUG */
+# define WARN_REFCOUNT(m,o,r) do { ; } while (0)
# define ON_DBG(m,x) do { ; } while (0)
# define DBG(m,x) do { ; } while (0)
# define DBG_FLUSH do { ; } while(0)
@@ -129,13 +137,11 @@ extern int mnt_run_test(struct libmnt_test *tests, int argc, char *argv[]);
#endif
/* utils.c */
-extern int endswith(const char *s, const char *sx)
- __attribute__((nonnull));
-extern int startswith(const char *s, const char *sx)
- __attribute__((nonnull));
-
extern char *stripoff_last_component(char *path);
+extern int mnt_valid_tagname(const char *tagname);
+extern int append_string(char **a, const char *b);
+
extern int is_file_empty(const char *name);
extern int mkdir_p(const char *path, mode_t mode);
@@ -200,12 +206,13 @@ struct libmnt_iter {
/*
- * This struct represents one entry in mtab/fstab/mountinfo file.
+ * This struct represents one entry in a mtab/fstab/mountinfo file.
* (note that fstab[1] means the first column from fstab, and so on...)
*/
struct libmnt_fs {
struct list_head ents;
+ int refcount; /* reference counter */
int id; /* mountinfo[1]: ID */
int parent; /* mountinfo[2]: parent */
dev_t devno; /* mountinfo[3]: st_dev */
@@ -240,6 +247,8 @@ struct libmnt_fs {
int flags; /* MNT_FS_* flags */
pid_t tid; /* /proc/<tid>/mountinfo otherwise zero */
+ char *comment; /* fstab comment */
+
void *userdata; /* library independent data */
};
@@ -261,7 +270,11 @@ struct libmnt_fs {
*/
struct libmnt_table {
int fmt; /* MNT_FMT_* file format */
- int nents; /* number of valid entries */
+ int nents; /* number of entries */
+ int refcount; /* reference counter */
+ int comms; /* enable/disable comment parsing */
+ char *comm_intro; /* First comment in file */
+ char *comm_tail; /* Last comment in file */
struct libmnt_cache *cache; /* canonicalized paths/tags cache */
@@ -273,6 +286,7 @@ struct libmnt_table {
struct list_head ents; /* list of entries (libmnt_fs) */
+ void *userdata;
};
extern struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt);
@@ -373,17 +387,13 @@ struct libmnt_context
#define MNT_FL_FORK (1 << 12)
#define MNT_FL_NOSWAPMATCH (1 << 13)
-#define MNT_FL_EXTERN_FS (1 << 15) /* cxt->fs is not private */
-#define MNT_FL_EXTERN_FSTAB (1 << 16) /* cxt->fstab is not private */
-#define MNT_FL_EXTERN_CACHE (1 << 17) /* cxt->cache is not private */
-
#define MNT_FL_MOUNTDATA (1 << 20)
#define MNT_FL_TAB_APPLIED (1 << 21) /* mtab/fstab merged to cxt->fs */
#define MNT_FL_MOUNTFLAGS_MERGED (1 << 22) /* MS_* flags was read from optstr */
#define MNT_FL_SAVED_USER (1 << 23)
#define MNT_FL_PREPARED (1 << 24)
#define MNT_FL_HELPER (1 << 25) /* [u]mount.<type> */
-#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by library */
+#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by the library */
#define MNT_FL_MOUNTOPTS_FIXED (1 << 27)
/* default flags */
diff --git a/libmount/src/optmap.c b/libmount/src/optmap.c
index 7c0a23508..5b25b8f29 100644
--- a/libmount/src/optmap.c
+++ b/libmount/src/optmap.c
@@ -58,6 +58,7 @@
* mount/mount.h.
*/
#include "mountP.h"
+#include "strutils.h"
/*
* fs-independent mount flags (built-in MNT_LINUX_MAP)
@@ -78,7 +79,7 @@ static const struct libmnt_optmap linux_flags_map[] =
{ "dirsync", MS_DIRSYNC }, /* synchronous directory modifications */
{ "remount", MS_REMOUNT, MNT_NOMTAB }, /* alter flags of mounted FS */
- { "bind", MS_BIND }, /* Remount part of tree elsewhere */
+ { "bind", MS_BIND }, /* Remount part of the tree elsewhere */
{ "rbind", MS_BIND | MS_REC }, /* Idem, plus mounted subtrees */
#ifdef MS_NOSUB
{ "sub", MS_NOSUB, MNT_INVERT }, /* allow submounts */
@@ -133,7 +134,7 @@ static const struct libmnt_optmap userspace_opts_map[] =
{ "defaults", 0, 0 }, /* default options */
{ "auto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_INVERT | MNT_NOMTAB }, /* Can be mounted using -a */
- { "noauto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_NOMTAB }, /* Can only be mounted explicitly */
+ { "noauto", MNT_MS_NOAUTO, MNT_NOHLPS | MNT_NOMTAB }, /* Can only be mounted explicitly */
{ "user[=]", MNT_MS_USER }, /* Allow ordinary user to mount (mtab) */
{ "nouser", MNT_MS_USER, MNT_INVERT | MNT_NOMTAB }, /* Forbid ordinary user to mount */
@@ -148,7 +149,7 @@ static const struct libmnt_optmap userspace_opts_map[] =
{ "nogroup", MNT_MS_GROUP, MNT_INVERT | MNT_NOMTAB }, /* Device group has no special privs */
/*
- * Note that traditional init scripts assume _netdev option in /etc/mtab to
+ * Note that traditional init scripts assume the _netdev option in /etc/mtab to
* umount network block devices on shutdown.
*/
{ "_netdev", MNT_MS_NETDEV }, /* Device requires network */
@@ -194,7 +195,7 @@ const struct libmnt_optmap *mnt_get_builtin_optmap(int id)
}
/*
- * Lookups for the @name in @maps and returns a map and in @mapent
+ * Looks up the @name in @maps and returns a map and in @mapent
* returns the map entry
*/
const struct libmnt_optmap *mnt_optmap_get_entry(
diff --git a/libmount/src/optstr.c b/libmount/src/optstr.c
index 5e9e70807..2cd55685e 100644
--- a/libmount/src/optstr.c
+++ b/libmount/src/optstr.c
@@ -8,10 +8,10 @@
/**
* SECTION: optstr
* @title: Options string
- * @short_description: low-level API for work with mount options
+ * @short_description: low-level API for working with mount options
*
- * This is simple and low-level API to work with mount options that are stored
- * in string.
+ * This is a simple and low-level API to working with mount options that are stored
+ * in a string.
*/
#include <ctype.h>
@@ -39,8 +39,8 @@ struct libmnt_optloc {
(e && (e)->name && !strchr((e)->name, '=') && !((e)->mask & MNT_PREFIX))
/*
- * Parses the first option from @optstr. The @optstr pointer is set to begin of
- * the next option.
+ * Parses the first option from @optstr. The @optstr pointer is set to the beginning
+ * of the next option.
*
* Returns -EINVAL on parse error, 1 at the end of optstr and 0 on success.
*/
@@ -72,12 +72,12 @@ static int mnt_optstr_parse_next(char **optstr, char **name, size_t *namesz,
for (p = optstr0; p && *p; p++) {
if (!start)
- start = p; /* begin of the option item */
+ start = p; /* beginning of the option item */
if (*p == '"')
open_quote ^= 1; /* reverse the status */
if (open_quote)
continue; /* still in quoted block */
- if (!sep && *p == '=')
+ if (!sep && p > start && *p == '=')
sep = p; /* name and value separator */
if (*p == ',')
stop = p; /* terminate the option item */
@@ -111,7 +111,7 @@ error:
}
/*
- * Locates the first option that match with @name. The @end is set to
+ * Locates the first option that matches @name. The @end is set to the
* char behind the option (it means ',' or \0).
*
* Returns negative number on parse error, 1 when not found and 0 on success.
@@ -150,11 +150,11 @@ static int mnt_optstr_locate_option(char *optstr, const char *name,
/**
* mnt_optstr_next_option:
- * @optstr: option string, returns position to next option
- * @name: returns option name
- * @namesz: returns option name length
- * @value: returns option value or NULL
- * @valuesz: returns option value length or zero
+ * @optstr: option string, returns the position of the next option
+ * @name: returns the option name
+ * @namesz: returns the option name length
+ * @value: returns the option value or NULL
+ * @valuesz: returns the option value length or zero
*
* Parses the first option in @optstr.
*
@@ -214,11 +214,11 @@ static int __mnt_optstr_append_option(char **optstr,
/**
* mnt_optstr_append_option:
- * @optstr: option string or NULL, returns reallocated string
+ * @optstr: option string or NULL, returns a reallocated string
* @name: value name
* @value: value
*
- * Returns: 0 on success or -1 in case of error. After error the @optstr should
+ * Returns: 0 on success or -1 in case of error. After an error the @optstr should
* be unmodified.
*/
int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
@@ -238,11 +238,11 @@ int mnt_optstr_append_option(char **optstr, const char *name, const char *value)
/**
* mnt_optstr_prepend_option:
- * @optstr: option string or NULL, returns reallocated string
+ * @optstr: option string or NULL, returns a reallocated string
* @name: value name
* @value: value
*
- * Returns: 0 on success or -1 in case of error. After error the @optstr should
+ * Returns: 0 on success or -1 in case of error. After an error the @optstr should
* be unmodified.
*/
int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value)
@@ -275,9 +275,9 @@ int mnt_optstr_prepend_option(char **optstr, const char *name, const char *value
/**
* mnt_optstr_get_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
- * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL
+ * @value: returns a pointer to the beginning of the value (e.g. name=VALUE) or NULL
* @valsz: returns size of the value or 0
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
@@ -306,7 +306,7 @@ int mnt_optstr_get_option(const char *optstr, const char *name,
/**
* mnt_optstr_deduplicate_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
*
* Removes all instances of @name except the last one.
@@ -331,12 +331,12 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
rc = mnt_optstr_locate_option(opt, name, &ol);
if (!rc) {
if (begin) {
- /* remove previous instance */
+ /* remove the previous instance */
size_t shift = strlen(*optstr);
mnt_optstr_remove_option_at(optstr, begin, end);
- /* now all offset are not valied anymore - recount */
+ /* now all the offsets are not valid anymore - recount */
shift -= strlen(*optstr);
ol.begin -= shift;
ol.end -= shift;
@@ -351,7 +351,7 @@ int mnt_optstr_deduplicate_option(char **optstr, const char *name)
}
/*
- * The result never starts or ends with comma or contains two commas
+ * The result never starts or ends with a comma or contains two commas
* (e.g. ",aaa,bbb" or "aaa,,bbb" or "aaa,")
*/
int mnt_optstr_remove_option_at(char **optstr, char *begin, char *end)
@@ -387,14 +387,14 @@ insert_value(char **str, char *pos, const char *substr, char **next)
/* is it necessary to prepend '=' before the substring ? */
sep = !(pos > *str && *(pos - 1) == '=');
- /* save an offset of the place where we need add substr */
+ /* save an offset of the place where we need to add substr */
posoff = pos - *str;
p = realloc(*str, strsz + sep + subsz + 1);
if (!p)
return -ENOMEM;
- /* zeroize new allocated memory -- valgind loves is... */
+ /* zeroize the newly allocated memory -- valgrind loves us... */
memset(p + strsz, 0, sep + subsz + 1);
/* set pointers to the reallocated string */
@@ -402,7 +402,7 @@ insert_value(char **str, char *pos, const char *substr, char **next)
pos = p + posoff;
if (possz)
- /* create a room for new substring */
+ /* create a room for the new substring */
memmove(pos + subsz + sep, pos, possz + 1);
if (sep)
*pos++ = '=';
@@ -420,11 +420,11 @@ insert_value(char **str, char *pos, const char *substr, char **next)
/**
* mnt_optstr_set_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option
* @value: new value or NULL
*
- * Set or unset option @value.
+ * Set or unset the option @value.
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
* of error.
@@ -473,7 +473,7 @@ int mnt_optstr_set_option(char **optstr, const char *name, const char *value)
/**
* mnt_optstr_remove_option:
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @name: requested option name
*
* Returns: 0 on success, 1 when not found the @name or negative number in case
@@ -510,13 +510,13 @@ int mnt_optstr_remove_option(char **optstr, const char *name)
*
* mnt_split_optstr(optstr, &u, NULL, NULL, MNT_NOMTAB, 0);
*
- * returns all userspace options, the options that does not belong to
+ * returns all userspace options, the options that do not belong to
* mtab are ignored.
*
* Note that FS options are all options that are undefined in MNT_USERSPACE_MAP
* or MNT_LINUX_MAP.
*
- * Returns: 0 on success, or negative number in case of error.
+ * Returns: 0 on success, or a negative number in case of error.
*/
int mnt_split_optstr(const char *optstr, char **user, char **vfs,
char **fs, int ignore_user, int ignore_vfs)
@@ -540,7 +540,7 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
if (user)
*user = NULL;
- while(!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
+ while (!mnt_optstr_next_option(&str, &name, &namesz, &val, &valsz)) {
int rc = 0;
const struct libmnt_optmap *ent = NULL;
const struct libmnt_optmap *m =
@@ -567,12 +567,18 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
rc = __mnt_optstr_append_option(fs, name, namesz,
val, valsz);
if (rc) {
- if (vfs)
+ if (vfs) {
free(*vfs);
- if (fs)
+ *vfs = NULL;
+ }
+ if (fs) {
free(*fs);
- if (user)
+ *fs = NULL;
+ }
+ if (user) {
free(*user);
+ *user = NULL;
+ }
return rc;
}
}
@@ -582,21 +588,21 @@ int mnt_split_optstr(const char *optstr, char **user, char **vfs,
/**
* mnt_optstr_get_options
- * @optstr: string with comma separated list of options
+ * @optstr: string with a comma separated list of options
* @subset: returns newly allocated string with options
* @map: options map
* @ignore: mask of the options that should be ignored
*
- * Extracts options from @optstr that belongs to the @map, for example:
+ * Extracts options from @optstr that belong to the @map, for example:
*
* mnt_optstr_get_options(optstr, &p,
* mnt_get_builtin_optmap(MNT_LINUX_MAP),
* MNT_NOMTAB);
*
- * the 'p' returns all VFS options, the options that does not belong to mtab
+ * the 'p' returns all VFS options, the options that do not belong to mtab
* are ignored.
*
- * Returns: 0 on success, or negative number in case of error.
+ * Returns: 0 on success, or a negative number in case of error.
*/
int mnt_optstr_get_options(const char *optstr, char **subset,
const struct libmnt_optmap *map, int ignore)
@@ -652,8 +658,8 @@ int mnt_optstr_get_options(const char *optstr, char **subset,
*
* "bind,noexec,foo,bar" --returns-> MS_BIND|MS_NOEXEC
*
- * Note that @flags are not zeroized by this function! This function set/unset
- * bites in the @flags only.
+ * Note that @flags are not zeroized by this function! This function sets/unsets
+ * bits in the @flags only.
*
* Returns: 0 on success or negative number in case of error
*/
@@ -747,8 +753,8 @@ int mnt_optstr_apply_flags(char **optstr, unsigned long flags,
fl = flags;
/*
- * There is a convetion that 'rw/ro' flags is always at the begin of
- * the string (athough the 'rw' is unnecessary).
+ * There is a convention that 'rw/ro' flags are always at the beginning of
+ * the string (although the 'rw' is unnecessary).
*/
if (map == mnt_get_builtin_optmap(MNT_LINUX_MAP)) {
const char *o = (fl & MS_RDONLY) ? "ro" : "rw";
@@ -774,7 +780,7 @@ int mnt_optstr_apply_flags(char **optstr, unsigned long flags,
if (next && *next) {
/*
* scan @optstr and remove options that are missing in
- * the @flags
+ * @flags
*/
while(!mnt_optstr_next_option(&next, &name, &namesz,
&val, &valsz)) {
@@ -856,7 +862,7 @@ err:
* modify @optstr and returns zero if libmount is compiled without SELinux
* support.
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
#ifndef HAVE_LIBSELINUX
int mnt_optstr_fix_secontext(char **optstr __attribute__ ((__unused__)),
@@ -910,7 +916,7 @@ int mnt_optstr_fix_secontext(char **optstr,
return -EINVAL;
- /* create quoted string from the raw context */
+ /* create a quoted string from the raw context */
sz = strlen((char *) raw);
if (!sz)
return -EINVAL;
@@ -947,8 +953,8 @@ static int set_uint_value(char **optstr, unsigned int num,
}
/*
- * @optstr: string with comma separated list of options
- * @value: pointer to the begin of the uid value
+ * @optstr: string with a comma separated list of options
+ * @value: pointer to the beginning of the uid value
* @valsz: size of the value
* @next: returns pointer to the next option (optional argument)
@@ -958,7 +964,7 @@ static int set_uint_value(char **optstr, unsigned int num,
* if (!mnt_optstr_get_option(optstr, "uid", &val, &valsz))
* mnt_optstr_fix_uid(&optstr, val, valsz, NULL);
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next)
{
@@ -998,14 +1004,14 @@ int mnt_optstr_fix_uid(char **optstr, char *value, size_t valsz, char **next)
}
/*
- * @optstr: string with comma separated list of options
- * @value: pointer to the begin of the uid value
+ * @optstr: string with a comma separated list of options
+ * @value: pointer to the beginning of the uid value
* @valsz: size of the value
* @next: returns pointer to the next option (optional argument)
* Translates "groupname" or "usergid" to the real GID.
*
- * Returns: 0 on success, negative number in case of error.
+ * Returns: 0 on success, a negative number in case of error.
*/
int mnt_optstr_fix_gid(char **optstr, char *value, size_t valsz, char **next)
{
@@ -1328,7 +1334,7 @@ int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
{ "--append", test_append, "<optstr> <name> [<value>] append value to optstr" },
- { "--prepend",test_prepend,"<optstr> <name> [<value>] prepend value to optstr" },
+ { "--prepend",test_prepend,"<optstr> <name> [<value>] prepend value to optstr" },
{ "--set", test_set, "<optstr> <name> [<value>] (un)set value" },
{ "--get", test_get, "<optstr> <name> search name in optstr" },
{ "--remove", test_remove, "<optstr> <name> remove name in optstr" },
diff --git a/libmount/src/tab.c b/libmount/src/tab.c
index 11a297814..b023504ad 100644
--- a/libmount/src/tab.c
+++ b/libmount/src/tab.c
@@ -11,9 +11,9 @@
* @short_description: container for entries from fstab, mtab or mountinfo
*
* Note that mnt_table_find_* functions are mount(8) compatible. These functions
- * try to find an entry in more iterations where the first attempt is always
+ * try to find an entry in more iterations, where the first attempt is always
* based on comparison with unmodified (non-canonicalized or un-evaluated)
- * paths or tags. For example fstab with two entries:
+ * paths or tags. For example a fstab with two entries:
* <informalexample>
* <programlisting>
* LABEL=foo /foo auto rw
@@ -39,7 +39,7 @@
* mnt_table_find_source(tb, "UUID=anyuuid", &fs);
* </programlisting>
* </informalexample>
- * will returns the first entry (if UUID matches with the device).
+ * will return the first entry (if UUID matches with the device).
*/
#include <blkid.h>
@@ -47,6 +47,8 @@
#include "strutils.h"
#include "loopdev.h"
+static int is_mountinfo(struct libmnt_table *tb);
+
/**
* mnt_new_table:
*
@@ -66,7 +68,7 @@ struct libmnt_table *mnt_new_table(void)
return NULL;
DBG(TAB, mnt_debug_h(tb, "alloc"));
-
+ tb->refcount = 1;
INIT_LIST_HEAD(&tb->ents);
return tb;
}
@@ -75,7 +77,8 @@ struct libmnt_table *mnt_new_table(void)
* mnt_reset_table:
* @tb: tab pointer
*
- * Dealocates all entries (filesystems) from the table
+ * Removes all entries (filesystems) from the table. The filesystems with zero
+ * reference count will be deallocated.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -89,7 +92,7 @@ int mnt_reset_table(struct libmnt_table *tb)
while (!list_empty(&tb->ents)) {
struct libmnt_fs *fs = list_entry(tb->ents.next,
struct libmnt_fs, ents);
- mnt_free_fs(fs);
+ mnt_table_remove_fs(tb, fs);
}
tb->nents = 0;
@@ -97,10 +100,46 @@ int mnt_reset_table(struct libmnt_table *tb)
}
/**
+ * mnt_ref_table:
+ * @tb: table pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount++;
+ /*DBG(FS, mnt_debug_h(tb, "ref=%d", tb->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_table:
+ * @tb: table pointer
+ *
+ * De-increments reference counter, on zero the @tb is automatically
+ * deallocated by mnt_free_table().
+ */
+void mnt_unref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount--;
+ /*DBG(FS, mnt_debug_h(tb, "unref=%d", tb->refcount));*/
+ if (tb->refcount <= 0)
+ mnt_free_table(tb);
+ }
+}
+
+
+/**
* mnt_free_table:
* @tb: tab pointer
*
- * Deallocates tab struct and all entries.
+ * Deallocates the table. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_table().
+ *
+ * The table entries (filesystems) are unrefrenced by mnt_reset_table() and
+ * cache by mnt_unref_cache().
*/
void mnt_free_table(struct libmnt_table *tb)
{
@@ -109,7 +148,12 @@ void mnt_free_table(struct libmnt_table *tb)
mnt_reset_table(tb);
+ WARN_REFCOUNT(TAB, tb, tb->refcount);
DBG(TAB, mnt_debug_h(tb, "free"));
+
+ mnt_unref_cache(tb->cache);
+ free(tb->comm_intro);
+ free(tb->comm_tail);
free(tb);
}
@@ -117,26 +161,228 @@ void mnt_free_table(struct libmnt_table *tb)
* mnt_table_get_nents:
* @tb: pointer to tab
*
- * Returns: number of valid entries in tab.
+ * Returns: number of entries in table.
*/
int mnt_table_get_nents(struct libmnt_table *tb)
{
- assert(tb);
return tb ? tb->nents : 0;
}
/**
+ * mnt_table_is_empty:
+ * @tb: pointer to tab
+ *
+ * Returns: 1 if the table is without filesystems, or 0.
+ */
+int mnt_table_is_empty(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb == NULL || list_empty(&tb->ents) ? 1 : 0;
+}
+
+/**
+ * mnt_table_set_userdata:
+ * @tb: pointer to tab
+ * @data: pointer to user data
+ *
+ * Sets pointer to the private user data.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_userdata(struct libmnt_table *tb, void *data)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ tb->userdata = data;
+ return 0;
+}
+
+/**
+ * mnt_table_get_userdata:
+ * @tb: pointer to tab
+ *
+ * Returns: pointer to user's data.
+ */
+void *mnt_table_get_userdata(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->userdata : NULL;
+}
+
+/**
+ * mnt_table_enable_comments:
+ * @tb: pointer to tab
+ * @enable: TRUE or FALSE
+ *
+ * Enables parsing of comments.
+ *
+ * The initial (intro) file comment is accessible by
+ * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
+ * entry has to be separated by blank line. The filesystem comments are
+ * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
+ * by mnt_table_get_trailing_comment().
+ *
+ * <informalexample>
+ * <programlisting>
+ * #
+ * # Intro comment
+ * #
+ *
+ * # this comments belongs to the first fs
+ * LABEL=foo /mnt/foo auto defaults 1 2
+ * # this comments belongs to the second fs
+ * LABEL=bar /mnt/bar auto defaults 1 2
+ * # tailing comment
+ * </programlisting>
+ * </informalexample>
+ */
+void mnt_table_enable_comments(struct libmnt_table *tb, int enable)
+{
+ assert(tb);
+ if (tb)
+ tb->comms = enable;
+}
+
+/**
+ * mnt_table_with_comments:
+ * @tb: pointer to table
+ *
+ * Returns: 1 if comments parsing is enabled, or 0.
+ */
+int mnt_table_with_comments(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comms : 0;
+}
+
+/**
+ * mnt_table_get_intro_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: initial comment in tb
+ */
+const char *mnt_table_get_intro_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_intro : NULL;
+}
+
+/**
+ * mnt_table_set_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment or NULL
+ *
+ * Sets the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_intro);
+ tb->comm_intro = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_intro, comm);
+}
+
+/**
+ * mnt_table_get_trailing_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: table trailing comment
+ */
+const char *mnt_table_get_trailing_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_tail : NULL;
+}
+
+/**
+ * mnt_table_set_trailing_comment
+ * @tb: pointer to tab
+ * @comm: comment string
+ *
+ * Sets the trailing comment in table.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_tail);
+ tb->comm_tail = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_trailing_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends to the trailing table comment.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_tail, comm);
+}
+
+/**
* mnt_table_set_cache:
* @tb: pointer to tab
* @mpc: pointer to struct libmnt_cache instance
*
- * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
+ * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
* cache is recommended for mnt_table_find_*() functions.
*
* The cache could be shared between more tabs. Be careful when you share the
* same cache between more threads -- currently the cache does not provide any
* locking method.
*
+ * This function increments cache refrence counter. It's recomented to use
+ * mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
+ * referenced by @tb only.
+ *
* See also mnt_new_cache().
*
* Returns: 0 on success or negative number in case of error.
@@ -146,6 +392,9 @@ int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
assert(tb);
if (!tb)
return -EINVAL;
+
+ mnt_ref_cache(mpc); /* new */
+ mnt_unref_cache(tb->cache); /* old */
tb->cache = mpc;
return 0;
}
@@ -167,7 +416,9 @@ struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
* @tb: tab pointer
* @fs: new entry
*
- * Adds a new entry to tab.
+ * Adds a new entry to tab and increment @fs reference counter. Don't forget to
+ * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
+ * referenced by the table only.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -179,11 +430,12 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+ mnt_ref_fs(fs);
list_add_tail(&fs->ents, &tb->ents);
+ tb->nents++;
DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
- tb->nents++;
return 0;
}
@@ -192,6 +444,10 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
* @tb: tab pointer
* @fs: new entry
*
+ * Removes the @fs from the table and de-increment reference counter of the @fs. The
+ * filesystem with zero reference counter will be deallocated. Don't forget to use
+ * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
+ *
* Returns: 0 on success or negative number in case of error.
*/
int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
@@ -201,7 +457,11 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+
list_del(&fs->ents);
+ INIT_LIST_HEAD(&fs->ents); /* otherwise FS still points to the list */
+
+ mnt_unref_fs(fs);
tb->nents--;
return 0;
}
@@ -211,18 +471,18 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
* @tb: mountinfo file (/proc/self/mountinfo)
* @root: returns pointer to the root filesystem (/)
*
- * The function uses parent ID from mountinfo file to determine root filesystem
+ * The function uses the parent ID from the mountinfo file to determine the root filesystem
* (the filesystem with the smallest ID). The function is designed mostly for
- * applications where is necessary to sort mountpoints by IDs to get the tree
+ * applications where it is necessary to sort mountpoints by IDs to get the tree
* of the mountpoints (e.g. findmnt default output).
*
- * If you're not sure than use
+ * If you're not sure, then use
*
* mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
*
- * this is more robust and usable for arbitrary tab file (including fstab).
+ * this is more robust and usable for arbitrary tab files (including fstab).
*
- * Returns: 0 on success or less then zero case of error.
+ * Returns: 0 on success or negative number in case of error.
*/
int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
{
@@ -233,16 +493,16 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
assert(tb);
assert(root);
- if (!tb || !root)
+ if (!tb || !root || !is_mountinfo(tb))
return -EINVAL;
DBG(TAB, mnt_debug_h(tb, "lookup root fs"));
+ *root = NULL;
+
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
int id = mnt_fs_get_parent_id(fs);
- if (!id)
- break; /* @tab is not mountinfo file? */
if (!*root || id < root_id) {
*root = fs;
@@ -250,7 +510,7 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
}
}
- return root_id ? 0 : -EINVAL;
+ return *root ? 0 : -EINVAL;
}
/**
@@ -260,10 +520,10 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
* @parent: parental FS
* @chld: returns the next child filesystem
*
- * Note that filesystems are returned in the order how was mounted (according to
+ * Note that filesystems are returned in the order of mounting (according to
* IDs in /proc/self/mountinfo).
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*/
int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs *parent, struct libmnt_fs **chld)
@@ -271,15 +531,13 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs *fs;
int parent_id, lastchld_id = 0, chld_id = 0;
- if (!tb || !itr || !parent)
+ if (!tb || !itr || !parent || !is_mountinfo(tb))
return -EINVAL;
- DBG(TAB, mnt_debug_h(tb, "lookup next child of %s",
+ DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'",
mnt_fs_get_target(parent)));
parent_id = mnt_fs_get_id(parent);
- if (!parent_id)
- return -EINVAL;
/* get ID of the previously returned child */
if (itr->head && itr->p != itr->head) {
@@ -298,7 +556,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
id = mnt_fs_get_id(fs);
- /* avoid infinite loop. This only happens in rare cases
+ /* avoid an infinite loop. This only happens in rare cases
* such as in early userspace when the rootfs is its own parent */
if (id == parent_id)
continue;
@@ -310,7 +568,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
}
}
- if (!chld_id)
+ if (!*chld)
return 1; /* end of iterator */
/* set the iterator to the @chld for the next call */
@@ -325,7 +583,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* @itr: iterator
* @fs: returns the next tab entry
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*
* Example:
* <informalexample>
@@ -334,11 +592,10 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* const char *dir = mnt_fs_get_target(fs);
* printf("mount point: %s\n", dir);
* }
- * mnt_free_table(fi);
* </programlisting>
* </informalexample>
*
- * lists all mountpoints from fstab in backward order.
+ * lists all mountpoints from fstab in reverse order.
*/
int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
{
@@ -363,14 +620,54 @@ int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct l
}
/**
+ * mnt_table_first_fs:
+ * @tb: tab pointer
+ * @fs: returns the first tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
+ * mnt_table_last_fs:
+ * @tb: tab pointer
+ * @fs: returns the last tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_last_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
* mnt_table_find_next_fs:
* @tb: table
* @itr: iterator
- * @match_func: function returns 1 or 0
+ * @match_func: function returning 1 or 0
* @userdata: extra data for match_func
* @fs: returns pointer to the next matching table entry
*
- * This function allows search in @tb.
+ * This function allows searching in @tb.
*
* Returns: negative number in case of error, 1 at end of table or 0 o success.
*/
@@ -431,7 +728,7 @@ int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct
* @path: directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Same like mnt_get_mountpoint(), but this function does not rely on
+ * Same as mnt_get_mountpoint(), except this function does not rely on
* st_dev numbers.
*
* Returns: a tab entry or NULL.
@@ -442,12 +739,12 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
{
char *mnt;
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: '%s'", path));
mnt = strdup(path);
if (!mnt)
@@ -478,10 +775,10 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
* @path: mountpoint directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are three iterations, first
- * with @path, second with realpath(@path) and third with realpath(@path)
+ * Try to lookup an entry in the given tab, three iterations are possible, the first
+ * with @path, the second with realpath(@path) and the third with realpath(@path)
* against realpath(fs->target). The 2nd and 3rd iterations are not performed
- * when @tb cache is not set (see mnt_table_set_cache()).
+ * when the @tb cache is not set (see mnt_table_set_cache()).
*
* Returns: a tab entry or NULL.
*/
@@ -494,12 +791,12 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
assert(tb);
assert(path);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup TARGET: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup TARGET: '%s'", path));
/* native @target */
mnt_reset_iter(&itr, direction);
@@ -510,6 +807,8 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical TARGET: '%s'", cn));
+
/* canonicalized paths in struct libmnt_table */
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -519,7 +818,7 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
/* non-canonicaled path in struct libmnt_table
* -- note that mountpoint in /proc/self/mountinfo is already
- * canonicalized by kernel
+ * canonicalized by the kernel
*/
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -545,11 +844,11 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
* @path: source path (devname or dirname) or NULL
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are four iterations, first
- * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
- * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
+ * Try to lookup an entry in the given tab, four iterations are possible, the first
+ * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
+ * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
*
- * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
+ * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
* set (see mnt_table_set_cache()).
*
* Note that NULL is a valid source path; it will be replaced with "none". The
@@ -561,17 +860,17 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
{
struct libmnt_iter itr;
struct libmnt_fs *fs = NULL;
- int ntags = 0;
+ int ntags = 0, nents;
char *cn;
const char *p;
assert(tb);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup srcpath: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup SRCPATH: '%s'", path));
/* native paths */
mnt_reset_iter(&itr, direction);
@@ -585,8 +884,12 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
if (!path || !tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical SRCPATH: '%s'", cn));
+
+ nents = mnt_table_get_nents(tb);
+
/* canonicalized paths in struct libmnt_table */
- if (ntags < mnt_table_get_nents(tb)) {
+ if (ntags < nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_streq_srcpath(fs, cn))
@@ -612,9 +915,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
return fs;
}
} else if (rc < 0 && errno == EACCES) {
- /* @path is unaccessible, try evaluate all TAGs in @tb
+ /* @path is inaccessible, try evaluating all TAGs in @tb
* by udev symlinks -- this could be expensive on systems
- * with huge fstab/mtab */
+ * with a huge fstab/mtab */
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *t, *v, *x;
if (mnt_fs_get_tag(fs, &t, &v))
@@ -629,7 +932,7 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
}
/* non-canonicalized paths in struct libmnt_table */
- if (ntags <= mnt_table_get_nents(tb)) {
+ if (ntags <= nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
@@ -655,9 +958,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
* @val: tag value
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, first attempt is lookup by @tag and
+ * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
* @val, for the second attempt the tag is evaluated (converted to the device
- * name) and mnt_table_find_srcpath() is preformed. The second attempt is not
+ * name) and mnt_table_find_srcpath() is performed. The second attempt is not
* performed when @tb cache is not set (see mnt_table_set_cache()).
* Returns: a tab entry or NULL.
@@ -672,7 +975,7 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
assert(tag);
assert(val);
- if (!tb || !tag || !val)
+ if (!tb || !tag || !*tag || !val)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -703,16 +1006,17 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
* @source: TAG or path
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * This is high-level API for mnt_table_find_{srcpath,tag}. You needn't to care
- * about @source format (device, LABEL, UUID, ...). This function parses @source
- * and calls mnt_table_find_tag() or mnt_table_find_srcpath().
+ * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
+ * about the @source format (device, LABEL, UUID, ...). This function parses
+ * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
*
* Returns: a tab entry or NULL.
*/
struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
const char *source, int direction)
{
- struct libmnt_fs *fs = NULL;
+ struct libmnt_fs *fs;
+ char *t = NULL, *v = NULL;
assert(tb);
@@ -721,20 +1025,15 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s", source));
-
- if (source && strchr(source, '=')) {
- char *tag, *val;
+ DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source));
- if (blkid_parse_tag_string(source, &tag, &val) == 0) {
-
- fs = mnt_table_find_tag(tb, tag, val, direction);
-
- free(tag);
- free(val);
- }
- } else
+ if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
fs = mnt_table_find_srcpath(tb, source, direction);
+ else
+ fs = mnt_table_find_tag(tb, t, v, direction);
+
+ free(t);
+ free(v);
return fs;
}
@@ -747,7 +1046,7 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
* This function is implemented by mnt_fs_match_source() and
- * mnt_fs_match_target() functions. It means that this is more expensive that
+ * mnt_fs_match_target() functions. It means that this is more expensive than
* others mnt_table_find_* function, because every @tab entry is fully evaluated.
*
* Returns: a tab entry or NULL.
@@ -761,7 +1060,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
assert(tb);
assert(target);
- if (!tb || !target)
+ if (!tb || !target || !*target || !source || !*source)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -785,7 +1084,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
* @devno: device number
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Note that zero could be valid device number for root pseudo filesystem (e.g.
+ * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
* tmpfs).
*
* Returns: a tab entry or NULL.
@@ -819,7 +1118,7 @@ struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
* tb: /proc/self/mountinfo
* fs: filesystem
* mountflags: MS_BIND or 0
- * fsroot: fs-root that will be probably used in the mountinfo file
+ * fsroot: fs-root that will probably be used in the mountinfo file
* for @fs after mount(2)
*
* For btrfs subvolumes this function returns NULL, but @fsroot properly set.
@@ -841,7 +1140,7 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
assert(fs);
assert(fsroot);
- DBG(TAB, mnt_debug("lookup fs-root for %s", mnt_fs_get_source(fs)));
+ DBG(TAB, mnt_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
fstype = mnt_fs_get_fstype(fs);
@@ -945,20 +1244,20 @@ static int is_mountinfo(struct libmnt_table *tb)
}
/**
- * mnt_table_is_mounted:
+ * mnt_table_is_fs__mounted:
* @tb: /proc/self/mountinfo file
* @fstab_fs: /etc/fstab entry
*
* Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
- * ignored. This function explicitly compares source, target and root of the
+ * ignored. This function explicitly compares the source, target and root of the
* filesystems.
*
* Note that source and target are canonicalized only if a cache for @tb is
* defined (see mnt_table_set_cache()). The target canonicalization may
- * triggers automount on autofs mountpoints!
+ * trigger automount on autofs mountpoints!
*
* Don't use it if you want to know if a device is mounted, just use
- * mnt_table_find_source() for the device.
+ * mnt_table_find_source() on the device.
*
* This function is designed mostly for "mount -a".
*
@@ -973,6 +1272,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
const char *src = NULL, *tgt = NULL;
char *xtgt = NULL;
int rc = 0;
+ dev_t devno = 0;
assert(tb);
assert(fstab_fs);
@@ -980,7 +1280,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
DBG(FS, mnt_debug_h(fstab_fs, "is FS mounted? [target=%s]",
mnt_fs_get_target(fstab_fs)));
- if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_get_nents(tb) == 0) {
+ if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_is_empty(tb)) {
DBG(FS, mnt_debug_h(fstab_fs, "- ignore (swap or no data)"));
return 0;
}
@@ -1004,6 +1304,14 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
if (src && tb->cache && !mnt_fs_is_pseudofs(fstab_fs))
src = mnt_resolve_spec(src, tb->cache);
+ if (src && root) {
+ struct stat st;
+
+ devno = mnt_fs_get_devno(fstab_fs);
+ if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
+ devno = st.st_rdev;
+ }
+
tgt = mnt_fs_get_target(fstab_fs);
if (!tgt || !src) {
@@ -1014,7 +1322,12 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
- if (!mnt_fs_streq_srcpath(fs, src)) {
+ int eq = mnt_fs_streq_srcpath(fs, src);
+
+ if (!eq && devno && mnt_fs_get_devno(fs) == devno)
+ eq = 1;
+
+ if (!eq) {
/* The source does not match. Maybe the source is a loop
* device backing file.
*/
@@ -1046,7 +1359,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
}
/*
- * Compare target, try to minimize number of situations when we
+ * Compare target, try to minimize the number of situations when we
* need to canonicalize the path to avoid readlink() on
* mountpoints.
*/
@@ -1076,10 +1389,10 @@ static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
{
fprintf(stderr, "%s:%d: parse error\n", filename, line);
- return 1; /* all errors are recoverable -- this is default */
+ return 1; /* all errors are recoverable -- this is the default */
}
-struct libmnt_table *create_table(const char *file)
+struct libmnt_table *create_table(const char *file, int comments)
{
struct libmnt_table *tb;
@@ -1089,6 +1402,7 @@ struct libmnt_table *create_table(const char *file)
if (!tb)
goto err;
+ mnt_table_enable_comments(tb, comments);
mnt_table_set_parser_errcb(tb, parser_errcb);
if (mnt_table_parse_file(tb, file) != 0)
@@ -1096,7 +1410,7 @@ struct libmnt_table *create_table(const char *file)
return tb;
err:
fprintf(stderr, "%s: parsing failed\n", file);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return NULL;
}
@@ -1106,7 +1420,7 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_fs *fs;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
@@ -1123,10 +1437,10 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
printf("COPY:\n");
mnt_fs_print_debug(fs, stdout);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
rc = 0;
done:
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1136,8 +1450,12 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_iter *itr = NULL;
struct libmnt_fs *fs;
int rc = -1;
+ int parse_comments = FALSE;
- tb = create_table(argv[1]);
+ if (argc == 3 && !strcmp(argv[2], "--comments"))
+ parse_comments = TRUE;
+
+ tb = create_table(argv[1], parse_comments);
if (!tb)
return -1;
@@ -1145,12 +1463,20 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
if (!itr)
goto done;
+ if (mnt_table_get_intro_comment(tb))
+ fprintf(stdout, "Initial comment:\n\"%s\"\n",
+ mnt_table_get_intro_comment(tb));
+
while(mnt_table_next_fs(tb, itr, &fs) == 0)
mnt_fs_print_debug(fs, stdout);
+
+ if (mnt_table_get_trailing_comment(tb))
+ fprintf(stdout, "Trailing comment:\n\"%s\"\n",
+ mnt_table_get_trailing_comment(tb));
rc = 0;
done:
mnt_free_iter(itr);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1169,7 +1495,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
file = argv[1], find = argv[2], what = argv[3];
- tb = create_table(file);
+ tb = create_table(file, FALSE);
if (!tb)
goto done;
@@ -1178,6 +1504,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
if (strcasecmp(find, "source") == 0)
fs = mnt_table_find_source(tb, what, dr);
@@ -1191,8 +1518,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
rc = 0;
}
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1213,13 +1539,14 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_cache *mpc = NULL;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
mpc = mnt_new_cache();
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
if (!fs)
@@ -1228,8 +1555,7 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1247,6 +1573,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_mountpoint(tb, argv[1], MNT_ITER_BACKWARD);
if (!fs)
@@ -1255,8 +1582,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1274,7 +1600,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
return -1;
}
- fstab = create_table(argv[1]);
+ fstab = create_table(argv[1], FALSE);
if (!fstab)
goto done;
@@ -1286,6 +1612,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
if (mnt_table_is_fs_mounted(tb, fs))
@@ -1300,9 +1627,8 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_table(fstab);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
+ mnt_unref_table(fstab);
mnt_free_iter(itr);
return rc;
}
@@ -1310,7 +1636,7 @@ done:
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
- { "--parse", test_parse, "<file> parse and print tab" },
+ { "--parse", test_parse, "<file> [--comments] parse and print tab" },
{ "--find-forward", test_find_fw, "<file> <source|target> <string>" },
{ "--find-backward", test_find_bw, "<file> <source|target> <string>" },
{ "--find-pair", test_find_pair, "<file> <source> <target>" },
diff --git a/libmount/src/tab_diff.c b/libmount/src/tab_diff.c
index f01f889f8..052278233 100644
--- a/libmount/src/tab_diff.c
+++ b/libmount/src/tab_diff.c
@@ -25,7 +25,7 @@ struct libmnt_tabdiff {
int nchanges; /* number of changes */
struct list_head changes; /* list with modified entries */
- struct list_head unused; /* list with unuused entries */
+ struct list_head unused; /* list with unused entries */
};
/**
@@ -54,6 +54,8 @@ static void free_tabdiff_entry(struct tabdiff_entry *de)
if (!de)
return;
list_del(&de->changes);
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
free(de);
}
@@ -89,7 +91,7 @@ void mnt_free_tabdiff(struct libmnt_tabdiff *df)
*
* The options @old_fs, @new_fs and @oper are optional.
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*/
int mnt_tabdiff_next_change(struct libmnt_tabdiff *df, struct libmnt_iter *itr,
struct libmnt_fs **old_fs, struct libmnt_fs **new_fs, int *oper)
@@ -124,9 +126,9 @@ static int tabdiff_reset(struct libmnt_tabdiff *df)
{
assert(df);
- DBG(DIFF, mnt_debug_h(df, "reseting"));
+ DBG(DIFF, mnt_debug_h(df, "resetting"));
- /* zeroize all entries and move them to the list of unuused
+ /* zeroize all entries and move them to the list of unused
*/
while (!list_empty(&df->changes)) {
struct tabdiff_entry *de = list_entry(df->changes.next,
@@ -135,6 +137,9 @@ static int tabdiff_reset(struct libmnt_tabdiff *df)
list_del(&de->changes);
list_add_tail(&de->changes, &df->unused);
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
+
de->new_fs = de->old_fs = NULL;
de->oper = 0;
}
@@ -164,6 +169,12 @@ static int tabdiff_add_entry(struct libmnt_tabdiff *df, struct libmnt_fs *old,
INIT_LIST_HEAD(&de->changes);
+ mnt_ref_fs(new);
+ mnt_ref_fs(old);
+
+ mnt_unref_fs(de->new_fs);
+ mnt_unref_fs(de->old_fs);
+
de->old_fs = old;
de->new_fs = new;
de->oper = oper;
@@ -280,6 +291,8 @@ int mnt_diff_tables(struct libmnt_tabdiff *df, struct libmnt_table *old_tab,
de = tabdiff_get_mount(df, src, mnt_fs_get_id(fs));
if (de) {
+ mnt_ref_fs(fs);
+ mnt_unref_fs(de->old_fs);
de->oper = MNT_TABDIFF_MOVE;
de->old_fs = fs;
} else
@@ -342,8 +355,8 @@ int test_diff(struct libmnt_test *ts, int argc, char *argv[])
rc = 0;
done:
- mnt_free_table(tb_old);
- mnt_free_table(tb_new);
+ mnt_unref_table(tb_old);
+ mnt_unref_table(tb_new);
mnt_free_tabdiff(diff);
mnt_free_iter(itr);
return rc;
diff --git a/libmount/src/tab_parse.c b/libmount/src/tab_parse.c
index e930fd841..38c48fdfa 100644
--- a/libmount/src/tab_parse.c
+++ b/libmount/src/tab_parse.c
@@ -47,7 +47,7 @@ static int next_number(char **s, int *num)
*s = end;
- /* valid end of number is space or terminator */
+ /* valid end of number is a space or a terminator */
if (*end == ' ' || *end == '\t' || *end == '\0')
return 0;
return -1;
@@ -82,7 +82,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s)
if (optstr && *optstr)
unmangle_string(optstr);
- /* note that __foo functions does not reallocate the string
+ /* note that __foo functions do not reallocate the string
*/
rc = __mnt_fs_set_source_ptr(fs, src);
if (!rc) {
@@ -128,7 +128,7 @@ static int mnt_parse_table_line(struct libmnt_fs *fs, char *s)
}
/*
- * Parses one line from mountinfo file
+ * Parses one line from a mountinfo file
*/
static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
{
@@ -158,7 +158,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
/* (7) optional fields, terminated by " - " */
p = strstr(s, " - ");
if (!p) {
- DBG(TAB, mnt_debug("mountinfo parse error: not found separator"));
+ DBG(TAB, mnt_debug("mountinfo parse error: separator not found"));
return -EINVAL;
}
if (p > s + 1)
@@ -174,9 +174,20 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
&fs->fs_optstr);
if (rc >= 10) {
+ size_t sz;
+
fs->flags |= MNT_FS_KERNEL;
fs->devno = makedev(maj, min);
+ /* remove "(deleted)" suffix */
+ sz = strlen(fs->target);
+ if (sz > PATH_DELETED_SUFFIX_SZ) {
+ char *p = fs->target + (sz - PATH_DELETED_SUFFIX_SZ);
+
+ if (strcmp(p, PATH_DELETED_SUFFIX) == 0)
+ *p = '\0';
+ }
+
unmangle_string(fs->root);
unmangle_string(fs->target);
unmangle_string(fs->vfs_optstr);
@@ -192,7 +203,7 @@ static int mnt_parse_mountinfo_line(struct libmnt_fs *fs, char *s)
src = NULL;
}
- /* merge VFS and FS options to the one string */
+ /* merge VFS and FS options to one string */
fs->optstr = mnt_fs_strdup_options(fs);
if (!fs->optstr)
rc = -ENOMEM;
@@ -323,8 +334,8 @@ static int mnt_parse_swaps_line(struct libmnt_fs *fs, char *s)
/*
* Returns {m,fs}tab or mountinfo file format (MNT_FMT_*)
*
- * Note that we aren't trying to guess utab file format, because this file has
- * to be always parsed by private libmount routines with explicitly defined
+ * Note that we aren't trying to guess the utab file format, because this file
+ * always has to be parsed by private libmount routines with an explicitly defined
* format.
*
* mountinfo: "<number> <number> ... "
@@ -344,10 +355,82 @@ static int guess_table_format(char *line)
return MNT_FMT_FSTAB; /* fstab, mtab or /proc/mounts */
}
+static int is_comment_line(char *line)
+{
+ char *p = skip_spaces(line);
+
+ if (p && (*p == '#' || *p == '\n'))
+ return 1;
+ return 0;
+}
+
+/* returns 1 if the last line in the @str is blank */
+static int is_terminated_by_blank(const char *str)
+{
+ size_t sz = str ? strlen(str) : 0;
+ const char *p = sz ? str + (sz - 1) : NULL;
+
+ if (!sz || !p || *p != '\n')
+ return 0; /* empty or not terminated by '\n' */
+ if (p == str)
+ return 1; /* only '\n' */
+ p--;
+ while (p >= str && (*p == ' ' || *p == '\t'))
+ p--;
+ return *p == '\n' ? 1 : 0;
+}
+
+/*
+ * Reads the next line from the file.
+ *
+ * Returns 0 if the line is a comment
+ * 1 if the line is not a comment
+ * <0 on error
+ */
+static int next_comment_line(char *buf, size_t bufsz,
+ FILE *f, char **last, int *nlines)
+{
+ if (fgets(buf, bufsz, f) == NULL)
+ return feof(f) ? 1 : -EINVAL;
+
+ ++*nlines;
+ *last = strchr(buf, '\n');
+
+ return is_comment_line(buf) ? 0 : 1;
+}
+
+static int append_comment(struct libmnt_table *tb,
+ struct libmnt_fs *fs,
+ const char *comm,
+ int eof)
+{
+ int rc, intro = mnt_table_get_nents(tb) == 0;
+
+ if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb)))
+ intro = 0;
+
+ DBG(TAB, mnt_debug_h(tb, "appending %s comment",
+ intro ? "intro" :
+ eof ? "trailing" : "fs"));
+ if (intro)
+ rc = mnt_table_append_intro_comment(tb, comm);
+ else if (eof) {
+ rc = mnt_table_set_trailing_comment(tb,
+ mnt_fs_get_comment(fs));
+ if (!rc)
+ rc = mnt_table_append_trailing_comment(tb, comm);
+ if (!rc)
+ rc = mnt_fs_set_comment(fs, NULL);
+ } else
+ rc = mnt_fs_append_comment(fs, comm);
+ return rc;
+}
+
/*
* Read and parse the next line from {fs,m}tab or mountinfo
*/
-static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f, struct libmnt_fs *fs,
+static int mnt_table_parse_next(struct libmnt_table *tb, FILE *f,
+ struct libmnt_fs *fs,
const char *filename, int *nlines)
{
char buf[BUFSIZ];
@@ -366,7 +449,7 @@ next_line:
++*nlines;
s = strchr (buf, '\n');
if (!s) {
- /* Missing final newline? Otherwise extremely */
+ /* Missing final newline? Otherwise an extremely */
/* long line - assume file was corrupted */
if (feof(f)) {
DBG(TAB, mnt_debug_h(tb,
@@ -379,6 +462,26 @@ next_line:
goto err;
}
}
+
+ /* comments parser */
+ if (tb->comms
+ && (tb->fmt == MNT_FMT_GUESS || tb->fmt == MNT_FMT_FSTAB)
+ && is_comment_line(buf)) {
+ do {
+ rc = append_comment(tb, fs, buf, feof(f));
+ if (!rc)
+ rc = next_comment_line(buf,
+ sizeof(buf),
+ f, &s, nlines);
+ } while (rc == 0);
+
+ if (rc == 1 && feof(f))
+ rc = append_comment(tb, fs, NULL, 1);
+ if (rc < 0)
+ return rc;
+
+ }
+
*s = '\0';
if (--s >= buf && *s == '\r')
*s = '\0';
@@ -420,7 +523,7 @@ err:
tb->fmt == MNT_FMT_FSTAB ? "tab" : "utab"));
/* by default all errors are recoverable, otherwise behavior depends on
- * errcb() function. See mnt_table_set_parser_errcb().
+ * the errcb() function. See mnt_table_set_parser_errcb().
*/
return tb->errcb ? tb->errcb(tb, filename, *nlines) : 1;
}
@@ -461,7 +564,7 @@ static int kernel_fs_postparse(struct libmnt_table *tb,
int rc = 0;
const char *src = mnt_fs_get_srcpath(fs);
- /* This is filesystem description from /proc, so we're in some process
+ /* This is a filesystem description from /proc, so we're in some process
* namespace. Let's remember the process PID.
*/
if (filename && *tid == -1)
@@ -538,8 +641,9 @@ int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filenam
if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO)
rc = kernel_fs_postparse(tb, fs, &tid, filename);
}
+ mnt_unref_fs(fs);
+
if (rc) {
- mnt_free_fs(fs);
if (rc == 1)
continue; /* recoverable error */
if (feof(f))
@@ -561,10 +665,10 @@ err:
* @tb: tab pointer
* @filename: file
*
- * Parses whole table (e.g. /etc/mtab) and appends new records to the @tab.
+ * Parses the whole table (e.g. /etc/mtab) and appends new records to the @tab.
*
* The libmount parser ignores broken (syntax error) lines, these lines are
- * reported to caller by errcb() function (see mnt_table_set_parser_errcb()).
+ * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()).
*
* Returns: 0 on success, negative number in case of error.
*/
@@ -663,7 +767,7 @@ static int __mnt_table_parse_dir(struct libmnt_table *tb, const char *dirname)
if (n <= 0)
return 0;
- /* let use "at" functions rather than play crazy games with paths... */
+ /* let's use "at" functions rather than playing crazy games with paths... */
dir = opendir(dirname);
if (!dir) {
r = -errno;
@@ -704,7 +808,7 @@ out:
*
* The directory:
* - files are sorted by strverscmp(3)
- * - files that starts with "." are ignored (e.g. ".10foo.fstab")
+ * - files that start with "." are ignored (e.g. ".10foo.fstab")
* - files without the ".fstab" extension are ignored
*
* Returns: 0 on success or negative number in case of error.
@@ -728,7 +832,7 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
if (tb) {
tb->fmt = fmt;
if (mnt_table_parse_file(tb, filename) != 0) {
- mnt_free_table(tb);
+ mnt_unref_table(tb);
tb = NULL;
}
}
@@ -740,7 +844,7 @@ struct libmnt_table *__mnt_new_table_from_file(const char *filename, int fmt)
* @filename: /etc/{m,fs}tab or /proc/self/mountinfo path
*
* Same as mnt_new_table() + mnt_table_parse_file(). Use this function for private
- * files only. This function does not allow to use error callback, so you
+ * files only. This function does not allow using the error callback, so you
* cannot provide any feedback to end-users about broken records in files (e.g.
* fstab).
*
@@ -767,7 +871,7 @@ struct libmnt_table *mnt_new_table_from_dir(const char *dirname)
return NULL;
tb = mnt_new_table();
if (tb && mnt_table_parse_dir(tb, dirname) != 0) {
- mnt_free_table(tb);
+ mnt_unref_table(tb);
tb = NULL;
}
return tb;
@@ -779,13 +883,13 @@ struct libmnt_table *mnt_new_table_from_dir(const char *dirname)
* @cb: pointer to callback function
*
* The error callback function is called by table parser (mnt_table_parse_file())
- * in case of syntax error. The callback function could be used for errors
+ * in case of a syntax error. The callback function could be used for error
* evaluation, libmount will continue/stop parsing according to callback return
* codes:
*
* <0 : fatal error (abort parsing)
- * 0 : success (parsing continue)
- * >0 : recoverable error (the line is ignored, parsing continue).
+ * 0 : success (parsing continues)
+ * >0 : recoverable error (the line is ignored, parsing continues).
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -800,7 +904,7 @@ int mnt_table_set_parser_errcb(struct libmnt_table *tb,
}
/*
- * Filter out entries during tab file parsing. If @cb returns 1 then the entry
+ * Filter out entries during tab file parsing. If @cb returns 1, then the entry
* is ignored.
*/
int mnt_table_set_parser_fltrcb(struct libmnt_table *tb,
@@ -851,7 +955,7 @@ int mnt_table_parse_swaps(struct libmnt_table *tb, const char *filename)
* @filename: overwrites default (/etc/fstab or $LIBMOUNT_FSTAB) or NULL
*
* This function parses /etc/fstab and appends new lines to the @tab. If the
- * @filename is a directory then mnt_table_parse_dir() is called.
+ * @filename is a directory, then mnt_table_parse_dir() is called.
*
* See also mnt_table_set_parser_errcb().
*
@@ -884,7 +988,7 @@ int mnt_table_parse_fstab(struct libmnt_table *tb, const char *filename)
}
/*
- * This function uses @uf to found corresponding record in @tb, then the record
+ * This function uses @uf to find a corresponding record in @tb, then the record
* from @tb is updated (user specific mount options are added).
*
* Note that @uf must contain only user specific mount options instead of
@@ -986,7 +1090,7 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
if (mnt_table_get_nents(tb) == 0)
return 0; /* empty, ignore utab */
/*
- * try to read user specific information from /run/mount/utabs
+ * try to read the user specific information from /run/mount/utabs
*/
utab = mnt_get_utab_path();
if (!utab || is_file_empty(utab))
@@ -1005,11 +1109,11 @@ int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
- /* merge user options into mountinfo from kernel */
+ /* merge user options into mountinfo from the kernel */
while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
mnt_table_merge_user_fs(tb, u_fs);
}
- mnt_free_table(u_tb);
+ mnt_unref_table(u_tb);
return 0;
}
diff --git a/libmount/src/tab_update.c b/libmount/src/tab_update.c
index 1e7f32be0..13f6f6ebe 100644
--- a/libmount/src/tab_update.c
+++ b/libmount/src/tab_update.c
@@ -10,10 +10,10 @@
* @title: Tables update
* @short_description: userspace mount information management
*
- * The struct libmnt_update provides abstraction to manage mount options in
- * userspace independently on system configuration. This low-level API works on
- * system with and without /etc/mtab. On systems without the regular /etc/mtab
- * file are userspace mount options (e.g. user=) stored to the /run/mount/utab
+ * The struct libmnt_update provides an abstraction to manage mount options in
+ * userspace independently of system configuration. This low-level API works on
+ * systems both with and without /etc/mtab. On systems without the regular /etc/mtab
+ * file, the userspace mount options (e.g. user=) are stored in the /run/mount/utab
* file.
*
* It's recommended to use high-level struct libmnt_context API.
@@ -70,8 +70,8 @@ void mnt_free_update(struct libmnt_update *upd)
DBG(UPDATE, mnt_debug_h(upd, "free"));
- mnt_free_fs(upd->fs);
- mnt_free_table(upd->mountinfo);
+ mnt_unref_fs(upd->fs);
+ mnt_unref_table(upd->mountinfo);
free(upd->target);
free(upd->filename);
free(upd);
@@ -125,7 +125,7 @@ int mnt_update_set_filename(struct libmnt_update *upd, const char *filename,
* mnt_update_get_filename:
* @upd: update
*
- * This function returns file name (e.g. /etc/mtab) for the up-dated file.
+ * This function returns the file name (e.g. /etc/mtab) of the up-dated file.
*
* Returns: pointer to filename that will be updated or NULL in case of error.
*/
@@ -140,7 +140,7 @@ const char *mnt_update_get_filename(struct libmnt_update *upd)
* @upd: update handler
*
* Returns: 1 if entry described by @upd is successfully prepared and will be
- * written to mtab/utab file.
+ * written to the mtab/utab file.
*/
int mnt_update_is_ready(struct libmnt_update *upd)
{
@@ -180,7 +180,7 @@ int mnt_update_set_fs(struct libmnt_update *upd, unsigned long mountflags,
DBG(UPDATE, mnt_fs_print_debug(fs, stderr));
}
- mnt_free_fs(upd->fs);
+ mnt_unref_fs(upd->fs);
free(upd->target);
upd->ready = FALSE;
upd->fs = NULL;
@@ -287,10 +287,10 @@ int mnt_update_force_rdonly(struct libmnt_update *upd, int rdonly)
}
/*
- * Allocates utab entry (upd->fs) for mount/remount. This function should be
+ * Allocates an utab entry (upd->fs) for mount/remount. This function should be
* called *before* mount(2) syscall. The @fs is used as a read-only template.
*
- * Returns: 0 on success, negative number on error, 1 if utabs update is
+ * Returns: 0 on success, negative number on error, 1 if utab's update is
* unnecessary.
*/
static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
@@ -350,14 +350,14 @@ static int utab_new_entry(struct libmnt_update *upd, struct libmnt_fs *fs,
return 0;
err:
free(u);
- mnt_free_fs(upd->fs);
+ mnt_unref_fs(upd->fs);
upd->fs = NULL;
return rc;
}
/*
* Sets fs-root and fs-type to @upd->fs according to the @fs template and
- * @mountfalgs. For MS_BIND mountflag it reads information about source
+ * @mountfalgs. For MS_BIND mountflag it reads information about the source
* filesystem from /proc/self/mountinfo.
*/
static int set_fs_root(struct libmnt_update *upd, struct libmnt_fs *fs,
@@ -408,13 +408,14 @@ err:
*/
static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
{
- const char *o, *src, *fstype;
+ const char *o, *src, *fstype, *comm;
char *m1, *m2, *m3, *m4;
int rc;
assert(fs);
assert(f);
+ comm = mnt_fs_get_comment(fs);
src = mnt_fs_get_source(fs);
fstype = mnt_fs_get_fstype(fs);
o = mnt_fs_get_options(fs);
@@ -425,6 +426,8 @@ static int fprintf_mtab_fs(FILE *f, struct libmnt_fs *fs)
m4 = o ? mangle(o) : "rw";
if (m1 && m2 && m3 && m4) {
+ if (comm)
+ fputs(comm, f);
rc = fprintf(f, "%s %s %s %s %d %d\n",
m1, m2, m3, m4,
mnt_fs_get_freq(fs),
@@ -527,6 +530,10 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
struct libmnt_fs *fs;
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+
+ if (tb->comms && mnt_table_get_intro_comment(tb))
+ fputs(mnt_table_get_intro_comment(tb), f);
+
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (upd->userspace_only)
rc = fprintf_utab_fs(f, fs);
@@ -538,6 +545,8 @@ static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
goto leave;
}
}
+ if (tb->comms && mnt_table_get_trailing_comment(tb))
+ fputs(mnt_table_get_trailing_comment(tb), f);
if (fflush(f) != 0) {
rc = -errno;
@@ -570,6 +579,99 @@ leave:
return rc;
}
+/**
+ * mnt_table_write_file
+ * @tb: parsed file (e.g. fstab)
+ * @file: target
+ *
+ * This function writes @tb to @file.
+ *
+ * Returns: 0 on success, negative number on error.
+ */
+int mnt_table_write_file(struct libmnt_table *tb, FILE *file)
+{
+ int rc = 0;
+ struct libmnt_iter itr;
+ struct libmnt_fs *fs;
+
+ if (tb->comms && mnt_table_get_intro_comment(tb))
+ fputs(mnt_table_get_intro_comment(tb), file);
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ rc = fprintf_mtab_fs(file, fs);
+ if (rc)
+ return rc;
+ }
+ if (tb->comms && mnt_table_get_trailing_comment(tb))
+ fputs(mnt_table_get_trailing_comment(tb), file);
+
+ if (fflush(file) != 0)
+ rc = -errno;
+
+ DBG(TAB, mnt_debug_h(tb, "write file done [rc=%d]", rc));
+ return rc;
+}
+
+/**
+ * mnt_table_replace_file
+ * @tb: parsed file (e.g. fstab)
+ * @filename: target
+ *
+ * This function replaces @file by the new content from @tb.
+ *
+ * Returns: 0 on success, negative number on error.
+ */
+int mnt_table_replace_file(struct libmnt_table *tb, const char *filename)
+{
+ int fd, rc = 0;
+ FILE *f;
+ char *uq = NULL;
+
+ DBG(TAB, mnt_debug_h(tb, "%s: replacing", filename));
+
+ fd = mnt_open_uniq_filename(filename, &uq);
+ if (fd < 0)
+ return fd; /* error */
+
+ f = fdopen(fd, "w" UL_CLOEXECSTR);
+ if (f) {
+ struct stat st;
+
+ mnt_table_write_file(tb, f);
+
+ if (fflush(f) != 0) {
+ rc = -errno;
+ DBG(UPDATE, mnt_debug("%s: fflush failed: %m", uq));
+ goto leave;
+ }
+
+ rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;
+
+ if (!rc && stat(filename, &st) == 0)
+ /* Copy uid/gid from the present file before renaming. */
+ rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;
+
+ fclose(f);
+ f = NULL;
+
+ if (!rc)
+ rc = rename(uq, filename) ? -errno : 0;
+ } else {
+ rc = -errno;
+ close(fd);
+ }
+
+leave:
+ if (f)
+ fclose(f);
+ unlink(uq);
+ free(uq);
+
+ DBG(TAB, mnt_debug_h(tb, "replace done [rc=%d]", rc));
+ return rc;
+}
+
static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
{
struct libmnt_fs *fs;
@@ -581,6 +683,8 @@ static int add_file_entry(struct libmnt_table *tb, struct libmnt_update *upd)
return -ENOMEM;
mnt_table_add_fs(tb, fs);
+ mnt_unref_fs(fs);
+
return update_table(upd, tb);
}
@@ -606,7 +710,7 @@ static int update_add_entry(struct libmnt_update *upd, struct libmnt_lock *lc)
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -632,13 +736,12 @@ static int update_remove_entry(struct libmnt_update *upd, struct libmnt_lock *lc
if (rem) {
mnt_table_remove_fs(tb, rem);
rc = update_table(upd, tb);
- mnt_free_fs(rem);
}
}
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -670,7 +773,7 @@ static int update_modify_target(struct libmnt_update *upd, struct libmnt_lock *l
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -712,7 +815,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
if (lc)
mnt_unlock_file(lc);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -724,7 +827,7 @@ static int update_modify_options(struct libmnt_update *upd, struct libmnt_lock *
* High-level API to update /etc/mtab (or private /run/mount/utab file).
*
* The @lc lock is optional and will be created if necessary. Note that
- * the automatically created lock blocks all signals.
+ * an automatically created lock blocks all signals.
*
* See also mnt_lock_block_signals() and mnt_context_get_lock().
*
@@ -794,7 +897,7 @@ static int update(const char *target, struct libmnt_fs *fs, unsigned long mountf
goto done;
}
- /* [... here should be mount(2) call ...] */
+ /* [... mount(2) call should be here...] */
rc = mnt_update_table(upd, NULL);
done:
@@ -815,7 +918,7 @@ static int test_add(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_set_options(fs, argv[4]);
rc = update(NULL, fs, 0);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
return rc;
}
@@ -838,7 +941,7 @@ static int test_move(struct libmnt_test *ts, int argc, char *argv[])
rc = update(NULL, fs, MS_MOVE);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
return rc;
}
@@ -853,17 +956,42 @@ static int test_remount(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_set_options(fs, argv[2]);
rc = update(NULL, fs, MS_REMOUNT);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
+ return rc;
+}
+
+static int test_replace(struct libmnt_test *ts, int argc, char *argv[])
+{
+ struct libmnt_fs *fs = mnt_new_fs();
+ struct libmnt_table *tb = mnt_new_table();
+ int rc;
+
+ if (argc < 3)
+ return -1;
+
+ mnt_table_enable_comments(tb, TRUE);
+ mnt_table_parse_fstab(tb, NULL);
+
+ mnt_fs_set_source(fs, argv[1]);
+ mnt_fs_set_target(fs, argv[2]);
+ mnt_fs_append_comment(fs, "# this is new filesystem\n");
+
+ mnt_table_add_fs(tb, fs);
+ mnt_unref_fs(fs);
+
+ rc = mnt_table_replace_file(tb, mnt_get_fstab_path());
+ mnt_unref_table(tb);
return rc;
}
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
- { "--add", test_add, "<src> <target> <type> <options> add line to mtab" },
+ { "--add", test_add, "<src> <target> <type> <options> add a line to mtab" },
{ "--remove", test_remove, "<target> MS_REMOUNT mtab change" },
{ "--move", test_move, "<old_target> <target> MS_MOVE mtab change" },
{ "--remount",test_remount, "<target> <options> MS_REMOUNT mtab change" },
+ { "--replace",test_replace, "<src> <target> Add a line to LIBMOUNT_FSTAB and replace the original file" },
{ NULL }
};
diff --git a/libmount/src/utils.c b/libmount/src/utils.c
index c328414f2..4111b595b 100644
--- a/libmount/src/utils.c
+++ b/libmount/src/utils.c
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
+#include <blkid.h>
#include "strutils.h"
#include "pathnames.h"
@@ -23,39 +24,33 @@
#include "env.h"
#include "match.h"
-int endswith(const char *s, const char *sx)
+int append_string(char **a, const char *b)
{
- ssize_t off;
+ size_t al, bl;
+ char *tmp;
- assert(s);
- assert(sx);
+ assert(a);
- off = strlen(s);
- if (!off)
+ if (!b || !*b)
return 0;
- off -= strlen(sx);
- if (off < 0)
- return 0;
-
- return !strcmp(s + off, sx);
-}
-
-int startswith(const char *s, const char *sx)
-{
- size_t off;
-
- assert(s);
- assert(sx);
+ if (!*a) {
+ *a = strdup(b);
+ return !*a ? -ENOMEM : 0;
+ }
- off = strlen(sx);
- if (!off)
- return 0;
+ al = strlen(*a);
+ bl = strlen(b);
- return !strncmp(s, sx, off);
+ tmp = realloc(*a, al + bl + 1);
+ if (!tmp)
+ return -ENOMEM;
+ *a = tmp;
+ memcpy((*a) + al, b, bl + 1);
+ return 0;
}
/*
- * Return 1 if the file does not accessible of empty
+ * Return 1 if the file is not accessible or empty
*/
int is_file_empty(const char *name)
{
@@ -65,6 +60,34 @@ int is_file_empty(const char *name)
return (stat(name, &st) != 0 || st.st_size == 0);
}
+int mnt_valid_tagname(const char *tagname)
+{
+ if (tagname && *tagname && (
+ strcmp("UUID", tagname) == 0 ||
+ strcmp("LABEL", tagname) == 0 ||
+ strcmp("PARTUUID", tagname) == 0 ||
+ strcmp("PARTLABEL", tagname) == 0))
+ return 1;
+
+ return 0;
+}
+
+/**
+ * mnt_tag_is_valid:
+ * @tag: NAME=value string
+ *
+ * Returns: 1 if the @tag is parsable and tag NAME= is supported by libmount, or 0.
+ */
+int mnt_tag_is_valid(const char *tag)
+{
+ char *t = NULL;
+ int rc = tag && blkid_parse_tag_string(tag, &t, NULL) == 0
+ && mnt_valid_tagname(t);
+
+ free(t);
+ return rc;
+}
+
int mnt_parse_offset(const char *str, size_t len, uintmax_t *res)
{
char *p;
@@ -105,8 +128,8 @@ char *stripoff_last_component(char *path)
}
/*
- * Note that the @target has to be absolute path (so at least "/"). The
- * @filename returns allocated buffer with last path component, for example:
+ * Note that the @target has to be an absolute path (so at least "/"). The
+ * @filename returns an allocated buffer with the last path component, for example:
*
* mnt_chdir_to_parent("/mnt/test", &buf) ==> chdir("/mnt"), buf="test"
*/
@@ -159,8 +182,9 @@ int mnt_chdir_to_parent(const char *target, char **filename)
if (!last || !*last)
memcpy(*filename, ".", 2);
else
- memcpy(*filename, last, strlen(last) + 1);
- }
+ memmove(*filename, last, strlen(last) + 1);
+ } else
+ free(buf);
return 0;
err:
free(buf);
@@ -168,7 +192,7 @@ err:
}
/*
- * Check if @path is on read-only filesystem independently on file permissions.
+ * Check if @path is on a read-only filesystem independently of file permissions.
*/
int mnt_is_readonly(const char *path)
{
@@ -187,7 +211,7 @@ int mnt_is_readonly(const char *path)
* accessible for the current rUID. (Note that euidaccess(2) does not
* check for EROFS at all).
*
- * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
+ * - for a read-write filesystem with a read-only VFS node (aka -o remount,ro,bind)
*/
{
struct timespec times[2];
@@ -208,7 +232,7 @@ int mnt_is_readonly(const char *path)
*
* Encode @str to be compatible with fstab/mtab
*
- * Returns: new allocated string or NULL in case of error.
+ * Returns: newly allocated string or NULL in case of error.
*/
char *mnt_mangle(const char *str)
{
@@ -221,7 +245,7 @@ char *mnt_mangle(const char *str)
*
* Decode @str from fstab/mtab
*
- * Returns: new allocated string or NULL in case of error.
+ * Returns: newly allocated string or NULL in case of error.
*/
char *mnt_unmangle(const char *str)
{
@@ -250,8 +274,9 @@ int mnt_fstype_is_pseudofs(const char *type)
"devpts",
"devtmpfs",
"dlmfs",
- "fuse.gvfs-fuse-daemon",
+ "efivarfs",
"fusectl",
+ "fuse.gvfs-fuse-daemon",
"hugetlbfs",
"mqueue",
"nfsd",
@@ -300,7 +325,7 @@ int mnt_fstype_is_netfs(const char *type)
* @type: filesystem type
* @pattern: filesystem name or comma delimited list of names
*
- * The @pattern list of filesystem can be prefixed with a global
+ * The @pattern list of filesystems can be prefixed with a global
* "no" prefix to invert matching of the whole list. The "no" could
* also be used for individual items in the @pattern list. So,
* "nofoo,bar" has the same meaning as "nofoo,nobar".
@@ -358,14 +383,14 @@ static int check_option(const char *haystack, size_t len,
* @optstr: options string
* @pattern: comma delimited list of options
*
- * The "no" could used for individual items in the @options list. The "no"
+ * The "no" could be used for individual items in the @options list. The "no"
* prefix does not have a global meaning.
*
* Unlike fs type matching, nonetdev,user and nonetdev,nouser have
* DIFFERENT meanings; each option is matched explicitly as specified.
*
- * The "no" prefix interpretation could be disable by "+" prefix, for example
- * "+noauto" matches if @optstr literally contains "noauto" string.
+ * The "no" prefix interpretation could be disabled by the "+" prefix, for example
+ * "+noauto" matches if @optstr literally contains the "noauto" string.
*
* "xxx,yyy,zzz" : "nozzz" -> False
*
@@ -495,7 +520,7 @@ static int get_filesystems(const char *filename, char ***filesystems, const char
}
/*
- * Always check @filesystems pointer!
+ * Always check the @filesystems pointer!
*
* man mount:
*
@@ -520,7 +545,7 @@ int mnt_get_filesystems(char ***filesystems, const char *pattern)
rc = get_filesystems(_PATH_PROC_FILESYSTEMS, filesystems, pattern);
if (rc == 1 && *filesystems)
- rc = 0; /* not found /proc/filesystems */
+ rc = 0; /* /proc/filesystems not found */
return rc;
}
@@ -536,7 +561,7 @@ static size_t get_pw_record_size(void)
}
/*
- * Returns allocated string with username or NULL.
+ * Returns an allocated string with username or NULL.
*/
char *mnt_get_username(const uid_t uid)
{
@@ -662,8 +687,8 @@ static int try_write(const char *filename)
* @mtab: returns path to mtab
* @writable: returns 1 if the file is writable
*
- * If the file does not exist and @writable argument is not NULL then it will
- * try to create the file
+ * If the file does not exist and @writable argument is not NULL, then it will
+ * try to create the file.
*
* Returns: 1 if /etc/mtab is a regular file, and 0 in case of error (check
* errno for more details).
@@ -684,7 +709,7 @@ int mnt_has_regular_mtab(const char **mtab, int *writable)
rc = lstat(filename, &st);
if (rc == 0) {
- /* file exist */
+ /* file exists */
if (S_ISREG(st.st_mode)) {
if (writable)
*writable = !try_write(filename);
@@ -708,7 +733,7 @@ done:
/*
* Don't export this to libmount API -- utab is private library stuff.
*
- * If the file does not exist and @writable argument is not NULL then it will
+ * If the file does not exist and @writable argument is not NULL, then it will
* try to create the directory (e.g. /run/mount) and the file.
*
* Returns: 1 if utab is a regular file, and 0 in case of
@@ -730,13 +755,13 @@ int mnt_has_regular_utab(const char **utab, int *writable)
rc = lstat(filename, &st);
if (rc == 0) {
- /* file exist */
+ /* file exists */
if (S_ISREG(st.st_mode)) {
if (writable)
*writable = !try_write(filename);
return 1;
}
- goto done; /* it's not regular file */
+ goto done; /* it's not a regular file */
}
if (writable) {
@@ -788,7 +813,7 @@ const char *mnt_get_fstab_path(void)
/**
* mnt_get_mtab_path:
*
- * This function returns *default* location of the mtab file. The result does
+ * This function returns the *default* location of the mtab file. The result does
* not have to be writable. See also mnt_has_regular_mtab().
*
* Returns: path to /etc/mtab or $LIBMOUNT_MTAB.
@@ -819,7 +844,7 @@ const char *mnt_get_utab_path(void)
}
-/* returns file descriptor or -errno, @name returns uniques filename
+/* returns file descriptor or -errno, @name returns a unique filename
*/
int mnt_open_uniq_filename(const char *filename, char **name)
{
@@ -836,12 +861,14 @@ int mnt_open_uniq_filename(const char *filename, char **name)
if (rc <= 0)
return -errno;
- /* This is for very old glibc and for compatibility with Posix where is
+ /* This is for very old glibc and for compatibility with Posix, which says
* nothing about mkstemp() mode. All sane glibc use secure mode (0600).
*/
oldmode = umask(S_IRGRP|S_IWGRP|S_IXGRP|
S_IROTH|S_IWOTH|S_IXOTH);
fd = mkostemp(n, O_RDWR|O_CREAT|O_EXCL|O_CLOEXEC);
+ if (fd < 0)
+ fd = -errno;
umask(oldmode);
if (fd >= 0 && name)
@@ -849,7 +876,7 @@ int mnt_open_uniq_filename(const char *filename, char **name)
else
free(n);
- return fd < 0 ? -errno : fd;
+ return fd;
}
/**
@@ -859,7 +886,7 @@ int mnt_open_uniq_filename(const char *filename, char **name)
* This function finds the mountpoint that a given path resides in. @path
* should be canonicalized. The returned pointer should be freed by the caller.
*
- * Returns: allocated string with target of the mounted device or NULL on error
+ * Returns: allocated string with the target of the mounted device or NULL on error
*/
char *mnt_get_mountpoint(const char *path)
{
@@ -929,7 +956,7 @@ char *mnt_get_fs_root(const char *path, const char *mnt)
/*
* Search for @name kernel command parametr.
*
- * Returns newly allocated string with parameter argument if the @name is
+ * Returns newly allocated string with a parameter argument if the @name is
* specified as "name=" or returns pointer to @name or returns NULL if not
* found.
*
@@ -979,7 +1006,7 @@ char *mnt_get_kernel_cmdline_option(const char *name)
if (p != buf && !isblank(*(p - 1)))
continue; /* no space before the option */
if (!val && *(p + len) != '\0' && !isblank(*(p + len)))
- continue; /* no space behind the option */
+ continue; /* no space after the option */
if (val) {
char *v = p + len;
@@ -1070,6 +1097,18 @@ int test_endswith(struct libmnt_test *ts, int argc, char *argv[])
return 0;
}
+int test_appendstr(struct libmnt_test *ts, int argc, char *argv[])
+{
+ char *str = strdup(argv[1]);
+ const char *ap = argv[2];
+
+ append_string(&str, ap);
+ printf("new string: '%s'\n", str);
+
+ free(str);
+ return 0;
+}
+
int test_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
{
char *path = canonicalize_path(argv[1]),
@@ -1165,6 +1204,7 @@ int main(int argc, char *argv[])
{ "--filesystems", test_filesystems, "[<pattern>] list /{etc,proc}/filesystems" },
{ "--starts-with", test_startswith, "<string> <prefix>" },
{ "--ends-with", test_endswith, "<string> <prefix>" },
+ { "--append-string", test_appendstr, "<string> <appendix>" },
{ "--mountpoint", test_mountpoint, "<path>" },
{ "--fs-root", test_fsroot, "<path>" },
{ "--cd-parent", test_chdir, "<path>" },
diff --git a/libmount/src/version.c b/libmount/src/version.c
index 00b7c03e7..b72956230 100644
--- a/libmount/src/version.c
+++ b/libmount/src/version.c
@@ -10,7 +10,7 @@
/**
* SECTION: version
* @title: Version functions
- * @short_description: functions to get library version.
+ * @short_description: functions to get the library version.
*/
#include <ctype.h>
@@ -70,11 +70,11 @@ int mnt_get_library_version(const char **ver_string)
/**
* mnt_get_library_features:
- * @features: returns pointer to the static array of strings, the array is
+ * @features: returns a pointer to the static array of strings, the array is
* terminated by NULL.
*
* Returns: number of items in the features array not including the last NULL,
- * or less then zero in case of error
+ * or less than zero in case of error
*
* Example:
* <informalexample>