(root)/
util-linux-2.39/
libmount/
python/
fs.c
       1  /*
       2   * Python bindings for the libmount library.
       3   *
       4   * Copyright (C) 2013, Red Hat, Inc. All rights reserved.
       5   * Written by Ondrej Oprala and Karel Zak
       6   *
       7   * This file is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 3 of the License, or (at your option) any later version.
      11   *
      12   * This file is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General Public
      18   * License along with this file; if not, write to the Free Software
      19   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      20   */
      21  
      22  /*
      23   * TODO:
      24   * mnt_fs_match_{source,target}
      25   * mnt_fs_get_{attribute,option}
      26   */
      27  
      28  #include "pylibmount.h"
      29  #include <errno.h>
      30  
      31  #define Fs_HELP "Fs(source=None, root=None, target=None, fstype=None, options=None, attributes=None, freq=0, passno=0)"
      32  
      33  static PyMemberDef Fs_members[] = {
      34  	{NULL}
      35  };
      36  
      37  static PyObject *Fs_get_tag(FsObject *self)
      38  {
      39  	const char *tag = NULL, *val = NULL;
      40  	PyObject *result;
      41  
      42  	if (mnt_fs_get_tag(self->fs, &tag, &val) != 0)
      43  		return NULL;
      44  
      45  	result = Py_BuildValue("(ss)", tag, val);
      46  	if (!result)
      47  		PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
      48  	return result;
      49  }
      50  
      51  static PyObject *Fs_get_id(FsObject *self)
      52  {
      53  	return PyObjectResultInt(mnt_fs_get_id(self->fs));
      54  }
      55  
      56  static PyObject *Fs_get_parent_id(FsObject *self)
      57  {
      58  	return PyObjectResultInt(mnt_fs_get_parent_id(self->fs));
      59  }
      60  
      61  static PyObject *Fs_get_devno(FsObject *self)
      62  {
      63  	return PyObjectResultInt(mnt_fs_get_devno(self->fs));
      64  }
      65  
      66  static void _dump_debug_string(const char *lead, const char *s, char quote)
      67  {
      68  	/* PySys_WriteStdout() will automatically truncate any '%s' token
      69  	 * longer than a certain length (documented as 1000 bytes, but we
      70  	 * give ourselves some margin here just in case).  The only way I
      71  	 * know to get around this is to print such strings in bite-sized
      72  	 * chunks.
      73  	 */
      74  	static const unsigned int _PY_MAX_LEN = 900;
      75  	static const char *_PY_MAX_LEN_FMT = "%.900s";
      76  	unsigned int len;
      77  
      78  	if (lead != NULL)
      79  		PySys_WriteStdout("%s", lead);
      80  
      81  	if (quote != 0)
      82  		PySys_WriteStdout("%c", quote);
      83  
      84  	for (len = strlen(s); len > _PY_MAX_LEN; len -= _PY_MAX_LEN, s += _PY_MAX_LEN)
      85  		PySys_WriteStdout(_PY_MAX_LEN_FMT, s);
      86  
      87  	if (len > 0)
      88  		PySys_WriteStdout(_PY_MAX_LEN_FMT, s);
      89  
      90  	if (quote != 0)
      91  		PySys_WriteStdout("%c\n", quote);
      92  	else
      93  		PySys_WriteStdout("\n");
      94  }
      95  
      96  #define Fs_print_debug_HELP "print_debug()\n\n"
      97  static PyObject *Fs_print_debug(FsObject *self)
      98  {
      99  	PySys_WriteStdout("------ fs: %p\n", self->fs);
     100  	_dump_debug_string("source: ", mnt_fs_get_source(self->fs), 0);
     101  	_dump_debug_string("target: ", mnt_fs_get_target(self->fs), 0);
     102  	_dump_debug_string("fstype: ", mnt_fs_get_fstype(self->fs), 0);
     103  
     104  	if (mnt_fs_get_options(self->fs))
     105  		_dump_debug_string("optstr: ", mnt_fs_get_options(self->fs), 0);
     106  	if (mnt_fs_get_vfs_options(self->fs))
     107  		_dump_debug_string("VFS-optstr: ", mnt_fs_get_vfs_options(self->fs), 0);
     108  	if (mnt_fs_get_fs_options(self->fs))
     109  		_dump_debug_string("FS-opstr: ", mnt_fs_get_fs_options(self->fs), 0);
     110  	if (mnt_fs_get_user_options(self->fs))
     111  		_dump_debug_string("user-optstr: ", mnt_fs_get_user_options(self->fs), 0);
     112  	if (mnt_fs_get_optional_fields(self->fs))
     113  		_dump_debug_string("optional-fields: ", mnt_fs_get_optional_fields(self->fs), '\'');
     114  	if (mnt_fs_get_attributes(self->fs))
     115  		_dump_debug_string("attributes: ", mnt_fs_get_attributes(self->fs), 0);
     116  
     117  	if (mnt_fs_get_root(self->fs))
     118  		_dump_debug_string("root:   ", mnt_fs_get_root(self->fs), 0);
     119  
     120  	if (mnt_fs_get_swaptype(self->fs))
     121  		_dump_debug_string("swaptype: ", mnt_fs_get_swaptype(self->fs), 0);
     122  	if (mnt_fs_get_size(self->fs))
     123  		PySys_WriteStdout("size: %jd\n", mnt_fs_get_size(self->fs));
     124  	if (mnt_fs_get_usedsize(self->fs))
     125  		PySys_WriteStdout("usedsize: %jd\n", mnt_fs_get_usedsize(self->fs));
     126  	if (mnt_fs_get_priority(self->fs))
     127  		PySys_WriteStdout("priority: %d\n", mnt_fs_get_priority(self->fs));
     128  
     129  	if (mnt_fs_get_bindsrc(self->fs))
     130  		_dump_debug_string("bindsrc: ", mnt_fs_get_bindsrc(self->fs), 0);
     131  	if (mnt_fs_get_freq(self->fs))
     132  		PySys_WriteStdout("freq:   %d\n", mnt_fs_get_freq(self->fs));
     133  	if (mnt_fs_get_passno(self->fs))
     134  		PySys_WriteStdout("pass:   %d\n", mnt_fs_get_passno(self->fs));
     135  	if (mnt_fs_get_id(self->fs))
     136  		PySys_WriteStdout("id:     %d\n", mnt_fs_get_id(self->fs));
     137  	if (mnt_fs_get_parent_id(self->fs))
     138  		PySys_WriteStdout("parent: %d\n", mnt_fs_get_parent_id(self->fs));
     139  	if (mnt_fs_get_devno(self->fs))
     140  		PySys_WriteStdout("devno:  %d:%d\n", major(mnt_fs_get_devno(self->fs)),
     141  						minor(mnt_fs_get_devno(self->fs)));
     142  	if (mnt_fs_get_tid(self->fs))
     143  		PySys_WriteStdout("tid:    %d\n", mnt_fs_get_tid(self->fs));
     144  	if (mnt_fs_get_comment(self->fs))
     145  		_dump_debug_string("comment: ", mnt_fs_get_comment(self->fs), '\'');
     146  	return UL_IncRef(self);
     147  }
     148  /*
     149   ** Fs getters/setters
     150   */
     151  
     152  static PyObject *Fs_get_comment(FsObject *self, void *closure __attribute__((unused)))
     153  {
     154  	return PyObjectResultStr(mnt_fs_get_comment(self->fs));
     155  }
     156  
     157  static int Fs_set_comment(FsObject *self, PyObject *value, void *closure __attribute__((unused)))
     158  {
     159  	char *comment = NULL;
     160  	int rc = 0;
     161  
     162  	if (!value) {
     163  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     164  		return -1;
     165  	}
     166  	if (!(comment = pystos(value)))
     167  		return -1;
     168  
     169  	rc = mnt_fs_set_comment(self->fs, comment);
     170  	if (rc) {
     171  		UL_RaiseExc(-rc);
     172  		return -1;
     173  	}
     174  	return 0;
     175  }
     176  /* source */
     177  static PyObject *Fs_get_source(FsObject *self)
     178  {
     179  	return PyObjectResultStr(mnt_fs_get_source(self->fs));
     180  }
     181  
     182  static int Fs_set_source(FsObject *self, PyObject *value, void *closure __attribute__((unused)))
     183  {
     184  	char *source = NULL;
     185  	int rc = 0;
     186  
     187  	if (!value) {
     188  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     189  		return -1;
     190  	}
     191  	if (!(source = pystos(value)))
     192  		return -1;
     193  
     194  	rc = mnt_fs_set_source(self->fs, source);
     195  	if (rc) {
     196  		UL_RaiseExc(-rc);
     197  		return -1;
     198  	}
     199  	return 0;
     200  }
     201  
     202  static PyObject *Fs_get_srcpath(FsObject *self)
     203  {
     204  	return PyObjectResultStr(mnt_fs_get_srcpath(self->fs));
     205  }
     206  
     207  static PyObject *Fs_get_root(FsObject *self)
     208  {
     209  	return PyObjectResultStr(mnt_fs_get_root(self->fs));
     210  }
     211  
     212  static int Fs_set_root(FsObject *self, PyObject *value, void *closure __attribute__((unused)))
     213  {
     214  	char *root = NULL;
     215  	int rc = 0;
     216  
     217  	if (!value) {
     218  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     219  		return -1;
     220  	}
     221  	if (!(root = pystos(value)))
     222  		return -1;
     223  
     224  	rc = mnt_fs_set_root(self->fs, root);
     225  	if (rc) {
     226  		UL_RaiseExc(-rc);
     227  		return -1;
     228  	}
     229  	return 0;
     230  }
     231  
     232  static PyObject *Fs_get_target(FsObject *self)
     233  {
     234  	return PyObjectResultStr(mnt_fs_get_target(self->fs));
     235  }
     236  
     237  static int Fs_set_target(FsObject *self, PyObject *value, void *closure __attribute__((unused)))
     238  {
     239  	char *target = NULL;
     240  	int rc = 0;
     241  
     242  	if (!value) {
     243  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     244  		return -1;
     245  	}
     246  	if (!(target = pystos(value)))
     247  		return -1;
     248  
     249  	rc = mnt_fs_set_target(self->fs, target);
     250  	if (rc) {
     251  		UL_RaiseExc(-rc);
     252  		return -1;
     253  	}
     254  	return 0;
     255  }
     256  
     257  static PyObject *Fs_get_fstype(FsObject *self)
     258  {
     259  	return PyObjectResultStr(mnt_fs_get_fstype(self->fs));
     260  }
     261  
     262  static int Fs_set_fstype(FsObject *self, PyObject *value,
     263  			void *closure __attribute__((unused)))
     264  {
     265  	char *fstype = NULL;
     266  	int rc = 0;
     267  
     268  	if (!value) {
     269  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     270  		return -1;
     271  	}
     272  	if (!(fstype = pystos(value)))
     273  		return -1;
     274  
     275  	rc = mnt_fs_set_fstype(self->fs, fstype);
     276  	if (rc) {
     277  		UL_RaiseExc(-rc);
     278  		return -1;
     279  	}
     280  	return 0;
     281  }
     282  
     283  static PyObject *Fs_get_options(FsObject *self)
     284  {
     285  	return PyObjectResultStr(mnt_fs_get_options(self->fs));
     286  }
     287  
     288  static int Fs_set_options(FsObject *self, PyObject *value,
     289  			void *closure __attribute__((unused)))
     290  {
     291  	char *options = NULL;
     292  	int rc = 0;
     293  
     294  	if (!value) {
     295  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     296  		return -1;
     297  	}
     298  	if (!(options = pystos(value)))
     299  		return -1;
     300  
     301  	rc = mnt_fs_set_options(self->fs, options);
     302  	if (rc) {
     303  		UL_RaiseExc(-rc);
     304  		return -1;
     305  	}
     306  	return 0;
     307  }
     308  
     309  static PyObject *Fs_get_vfs_options(FsObject *self)
     310  {
     311  	return PyObjectResultStr(mnt_fs_get_vfs_options(self->fs));
     312  }
     313  
     314  
     315  static PyObject *Fs_get_optional_fields(FsObject *self)
     316  {
     317  	return PyObjectResultStr(mnt_fs_get_optional_fields(self->fs));
     318  }
     319  
     320  
     321  static PyObject *Fs_get_fs_options(FsObject *self)
     322  {
     323  	return PyObjectResultStr(mnt_fs_get_fs_options(self->fs));
     324  }
     325  
     326  
     327  static PyObject *Fs_get_user_options(FsObject *self)
     328  {
     329  	return PyObjectResultStr(mnt_fs_get_user_options(self->fs));
     330  }
     331  
     332  
     333  static PyObject *Fs_get_attributes(FsObject *self)
     334  {
     335  	return PyObjectResultStr(mnt_fs_get_attributes(self->fs));
     336  }
     337  
     338  static int Fs_set_attributes(FsObject *self, PyObject *value,
     339  			void *closure __attribute__((unused)))
     340  {
     341  	char *attributes = NULL;
     342  	int rc = 0;
     343  
     344  	if (!value) {
     345  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     346  		return -1;
     347  	}
     348  	if (!(attributes = pystos(value)))
     349  		return -1;
     350  
     351  	rc = mnt_fs_set_attributes(self->fs, attributes);
     352  	if (rc) {
     353  		UL_RaiseExc(-rc);
     354  		return -1;
     355  	}
     356  	return 0;
     357  }
     358  
     359  static PyObject *Fs_get_freq(FsObject *self, void *closure __attribute__((unused)))
     360  {
     361  	return PyObjectResultInt(mnt_fs_get_freq(self->fs));
     362  }
     363  
     364  static int Fs_set_freq(FsObject *self, PyObject *value,
     365  				void *closure __attribute__((unused)))
     366  {
     367  	int freq = 0;
     368  
     369  	if (!value) {
     370  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     371  		return -1;
     372  
     373  	}
     374  
     375  	if (!PyLong_Check(value)) {
     376  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     377  		return -1;
     378  	}
     379  
     380  	freq = PyLong_AsLong(value);
     381  	if (freq == -1 && PyErr_Occurred()) {
     382  		PyErr_SetString(PyExc_RuntimeError, "type conversion failed");
     383  		return -1;
     384  	}
     385  	return mnt_fs_set_freq(self->fs, freq);
     386  }
     387  
     388  static PyObject *Fs_get_passno(FsObject *self)
     389  {
     390  	return PyObjectResultInt(mnt_fs_get_passno(self->fs));
     391  }
     392  
     393  static int Fs_set_passno(FsObject *self, PyObject *value, void *closure __attribute__((unused)))
     394  {
     395  	int passno = 0;
     396  
     397  	if (!value) {
     398  		PyErr_SetString(PyExc_TypeError, NODEL_ATTR);
     399  		return -1;
     400  	}
     401  
     402  	if (!PyLong_Check(value)) {
     403  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     404  		return -1;
     405  	}
     406  
     407  	passno = PyLong_AsLong(value);
     408  	if (passno == -1 && PyErr_Occurred()) {
     409  		PyErr_SetString(PyExc_RuntimeError, "type conversion failed");
     410  		return -1;
     411  	}
     412  	return mnt_fs_set_passno(self->fs, passno);
     413  }
     414  
     415  static PyObject *Fs_get_swaptype(FsObject *self)
     416  {
     417  	return PyObjectResultStr(mnt_fs_get_swaptype(self->fs));
     418  }
     419  
     420  static PyObject *Fs_get_size(FsObject *self)
     421  {
     422  	return PyObjectResultInt(mnt_fs_get_size(self->fs));
     423  }
     424  
     425  static PyObject *Fs_get_usedsize(FsObject *self)
     426  {
     427  	return PyObjectResultInt(mnt_fs_get_usedsize(self->fs));
     428  }
     429  
     430  static PyObject *Fs_get_priority(FsObject *self)
     431  {
     432  	return PyObjectResultInt(mnt_fs_get_priority(self->fs));
     433  }
     434  
     435  #define Fs_get_propagation_HELP "get_propagation(flags)\n\n\
     436  Note that this function set flags to zero if not found any propagation flag\n\
     437  in mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored\n\
     438  in the mountinfo file.\n\
     439  \n\
     440  Returns self or raises an exception in case of an error."
     441  static PyObject *Fs_get_propagation(FsObject *self)
     442  {
     443  	unsigned long flags;
     444  	int rc;
     445  
     446  	rc =  mnt_fs_get_propagation(self->fs, &flags);
     447  	return rc ? UL_RaiseExc(-rc) : PyObjectResultInt(flags);
     448  }
     449  
     450  static PyObject *Fs_get_tid(FsObject *self)
     451  {
     452  	return PyObjectResultInt(mnt_fs_get_tid(self->fs));
     453  }
     454  
     455  #define Fs_is_kernel_HELP "is_kernel()\n\nReturns 1 if the filesystem " \
     456  			  "description is read from kernel e.g. /proc/mounts."
     457  static PyObject *Fs_is_kernel(FsObject *self)
     458  {
     459  	return PyBool_FromLong(mnt_fs_is_kernel(self->fs));
     460  }
     461  
     462  #define Fs_is_netfs_HELP "is_netfs()\n\nReturns 1 if the filesystem is " \
     463  			 "a network filesystem"
     464  static PyObject *Fs_is_netfs(FsObject *self)
     465  {
     466  	return PyBool_FromLong(mnt_fs_is_netfs(self->fs));
     467  }
     468  
     469  #define Fs_is_pseudofs_HELP "is_pseudofs()\n\nReturns 1 if the filesystem is "\
     470  			    "a pseudo fs type (proc, cgroups)"
     471  static PyObject *Fs_is_pseudofs(FsObject *self)
     472  {
     473  	return PyBool_FromLong(mnt_fs_is_pseudofs(self->fs));
     474  }
     475  
     476  #define Fs_is_swaparea_HELP "is_swaparea()\n\nReturns 1 if the filesystem " \
     477  			    "uses \"swap\" as a type"
     478  static PyObject *Fs_is_swaparea(FsObject *self)
     479  {
     480  	return PyBool_FromLong(mnt_fs_is_swaparea(self->fs));
     481  }
     482  
     483  #define Fs_append_attributes_HELP "append_attributes(optstr)\n\n" \
     484  				  "Appends mount attributes."
     485  static PyObject *Fs_append_attributes(FsObject *self, PyObject *args, PyObject *kwds)
     486  {
     487  	char *kwlist[] = {"optstr", NULL};
     488  	char *optstr = NULL;
     489  	int rc;
     490  
     491  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) {
     492  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     493  		return NULL;
     494  	}
     495  	rc = mnt_fs_append_attributes(self->fs, optstr);
     496  	return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
     497  }
     498  
     499  #define Fs_append_options_HELP "append_options(optstr)\n\n" \
     500  			"Parses (splits) optstr and appends results to VFS, " \
     501  			"FS and userspace lists of options."
     502  static PyObject *Fs_append_options(FsObject *self, PyObject *args, PyObject *kwds)
     503  {
     504  	char *kwlist[] = {"optstr", NULL};
     505  	char *optstr = NULL;
     506  	int rc;
     507  
     508  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) {
     509  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     510  		return NULL;
     511  	}
     512  	rc = mnt_fs_append_options(self->fs, optstr);
     513  	return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
     514  }
     515  
     516  #define Fs_prepend_attributes_HELP "prepend_attributes(optstr)\n\n" \
     517  				   "Prepends mount attributes."
     518  static PyObject *Fs_prepend_attributes(FsObject *self, PyObject *args, PyObject *kwds)
     519  {
     520  	char *kwlist[] = {"optstr", NULL};
     521  	char *optstr = NULL;
     522  	int rc;
     523  
     524  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) {
     525  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     526  		return NULL;
     527  	}
     528  	rc = mnt_fs_prepend_attributes(self->fs, optstr);
     529  	return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
     530  }
     531  
     532  #define Fs_prepend_options_HELP "prepend_options(optstr)\n\n" \
     533  			"Parses (splits) optstr and prepends results to VFS, " \
     534  			"FS and userspace lists of options."
     535  static PyObject *Fs_prepend_options(FsObject *self, PyObject *args, PyObject *kwds)
     536  {
     537  	char *kwlist[] = {"optstr", NULL};
     538  	char *optstr = NULL;
     539  	int rc;
     540  
     541  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &optstr)) {
     542  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     543  		return NULL;
     544  	}
     545  	rc = mnt_fs_prepend_options(self->fs, optstr);
     546  	return rc ? UL_RaiseExc(-rc) : UL_IncRef(self);
     547  }
     548  
     549  #define Fs_match_fstype_HELP "match_fstype(pattern)\n\n" \
     550  		"pattern: filesystem name or comma delimited list(string) of names\n\n" \
     551  		"The pattern list of filesystem can be prefixed with a global\n" \
     552  		"\"no\" prefix to invert matching of the whole list. The \"no\" could\n" \
     553  		"also be used for individual items in the pattern list. So,\n" \
     554  		"\"nofoo,bar\" has the same meaning as \"nofoo,nobar\".\n" \
     555  		"\"bar\" : \"nofoo,bar\"	-> False   (global \"no\" prefix)\n" \
     556  		"\"bar\" : \"foo,bar\"		-> True\n" \
     557  		"\"bar\" : \"foo,nobar\"	-> False\n\n" \
     558  		"Returns True if type is matching, else False."
     559  static PyObject *Fs_match_fstype(FsObject *self, PyObject *args, PyObject *kwds)
     560  {
     561  	char *kwlist[] = {"pattern", NULL};
     562  	char *pattern = NULL;
     563  
     564  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &pattern)) {
     565  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     566  		return NULL;
     567  	}
     568  	return PyBool_FromLong(mnt_fs_match_fstype(self->fs, pattern));
     569  }
     570  
     571  #define Fs_match_options_HELP "match_options(options)\n\n" \
     572  		"options: comma delimited list of options (and nooptions)\n" \
     573  		"Returns True if fs type is matching to options else False."
     574  static PyObject *Fs_match_options(FsObject *self, PyObject *args, PyObject *kwds)
     575  {
     576  	char *kwlist[] = {"options", NULL};
     577  	char *options = NULL;
     578  
     579  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &options)) {
     580  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     581  		return NULL;
     582  	}
     583  	return PyBool_FromLong(mnt_fs_match_options(self->fs, options));
     584  }
     585  
     586  #define Fs_streq_srcpath_HELP "streq_srcpath(srcpath)\n\n" \
     587  		"Compares fs source path with path. The tailing slash is ignored.\n" \
     588  		"Returns True if fs source path equal to path, otherwise False."
     589  static PyObject *Fs_streq_srcpath(FsObject *self, PyObject *args, PyObject *kwds)
     590  {
     591  	char *kwlist[] = {"srcpath", NULL};
     592  	char *srcpath = NULL;
     593  
     594  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &srcpath)) {
     595  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     596  		return NULL;
     597  	}
     598  	return PyBool_FromLong(mnt_fs_streq_srcpath(self->fs, srcpath));
     599  }
     600  
     601  #define Fs_streq_target_HELP "streq_target(target)\n\n" \
     602  		"Compares fs target path with path. The tailing slash is ignored.\n" \
     603  		"See also Fs.match_target().\n" \
     604  		"Returns True if fs target path equal to path, otherwise False."
     605  static PyObject *Fs_streq_target(FsObject *self, PyObject *args, PyObject *kwds)
     606  {
     607  	char *kwlist[] = {"target", NULL};
     608  	char *target = NULL;
     609  
     610  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &target)) {
     611  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     612  		return NULL;
     613  	}
     614  	return PyBool_FromLong(mnt_fs_streq_target(self->fs, target));
     615  }
     616  
     617  #define Fs_copy_fs_HELP "copy_fs(dest=None)\n\n" \
     618  		"If dest is None, a new object is created, if any fs " \
     619  		"field is already set, then the field is NOT overwritten."
     620  static PyObject *Fs_copy_fs(FsObject *self, PyObject *args, PyObject *kwds);
     621  
     622  static PyMethodDef Fs_methods[] = {
     623  	{"get_propagation",	(PyCFunction)Fs_get_propagation, METH_NOARGS, Fs_get_propagation_HELP},
     624  	{"mnt_fs_append_attributes",	(PyCFunction)Fs_append_attributes, METH_VARARGS|METH_KEYWORDS, Fs_append_attributes_HELP},
     625  	{"append_options",	(PyCFunction)Fs_append_options, METH_VARARGS|METH_KEYWORDS, Fs_append_options_HELP},
     626  	{"mnt_fs_prepend_attributes",	(PyCFunction)Fs_prepend_attributes, METH_VARARGS|METH_KEYWORDS, Fs_prepend_attributes_HELP},
     627  	{"prepend_options",	(PyCFunction)Fs_prepend_options, METH_VARARGS|METH_KEYWORDS, Fs_prepend_options_HELP},
     628  	{"copy_fs",		(PyCFunction)Fs_copy_fs, METH_VARARGS|METH_KEYWORDS, Fs_copy_fs_HELP},
     629  	{"is_kernel",		(PyCFunction)Fs_is_kernel, METH_NOARGS, Fs_is_kernel_HELP},
     630  	{"is_netfs",		(PyCFunction)Fs_is_netfs, METH_NOARGS, Fs_is_netfs_HELP},
     631  	{"is_pseudofs",		(PyCFunction)Fs_is_pseudofs, METH_NOARGS, Fs_is_pseudofs_HELP},
     632  	{"is_swaparea",		(PyCFunction)Fs_is_swaparea, METH_NOARGS, Fs_is_swaparea_HELP},
     633  	{"match_fstype",	(PyCFunction)Fs_match_fstype, METH_VARARGS|METH_KEYWORDS, Fs_match_fstype_HELP},
     634  	{"match_options",	(PyCFunction)Fs_match_options, METH_VARARGS|METH_KEYWORDS, Fs_match_options_HELP},
     635  	{"streq_srcpath",	(PyCFunction)Fs_streq_srcpath, METH_VARARGS|METH_KEYWORDS, Fs_streq_srcpath_HELP},
     636  	{"streq_target",	(PyCFunction)Fs_streq_target, METH_VARARGS|METH_KEYWORDS, Fs_streq_target_HELP},
     637  	{"print_debug",		(PyCFunction)Fs_print_debug, METH_NOARGS, Fs_print_debug_HELP},
     638  	{NULL}
     639  };
     640  
     641  static void Fs_destructor(FsObject *self)
     642  {
     643  	DBG(FS, pymnt_debug_h(self->fs, "destructor py-obj: %p, py-refcnt=%d",
     644  				self, (int) ((PyObject *) self)->ob_refcnt));
     645  	mnt_unref_fs(self->fs);
     646  	PyFree(self);
     647  }
     648  
     649  static PyObject *Fs_new(PyTypeObject *type, PyObject *args __attribute__((unused)),
     650  		PyObject *kwds __attribute__((unused)))
     651  {
     652  	FsObject *self = (FsObject*)type->tp_alloc(type, 0);
     653  
     654  	if (self) {
     655  		self->fs = NULL;
     656  		DBG(FS, pymnt_debug_h(self, "new"));
     657  	}
     658  	return (PyObject *) self;
     659  }
     660  
     661  static int Fs_init(FsObject *self, PyObject *args, PyObject *kwds)
     662  {
     663  	char *source = NULL, *root = NULL, *target = NULL;
     664  	char *fstype = NULL, *options = NULL, *attributes =NULL;
     665  	int freq = 0; int passno = 0;
     666  	int rc = 0;
     667  	char *kwlist[] = {
     668  		"source", "root", "target",
     669  		"fstype", "options", "attributes",
     670  		"freq", "passno", NULL
     671  	};
     672  
     673  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|ssssssii", kwlist,
     674  				&source, &root, &target, &fstype, &options,
     675  				&attributes, &freq, &passno)) {
     676  		PyErr_SetString(PyExc_TypeError, "Invalid type");
     677  		return -1;
     678  	}
     679  
     680  	DBG(FS, pymnt_debug_h(self, "init"));
     681  
     682  	if (self->fs)
     683  		mnt_unref_fs(self->fs);
     684  
     685  	self->fs = mnt_new_fs();		/* new FS with refcount=1 */
     686  
     687  	if (source && (rc = mnt_fs_set_source(self->fs, source))) {
     688  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     689  		return rc;
     690  	}
     691  	if (root && (rc = mnt_fs_set_root(self->fs, root))) {
     692  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     693  		return rc;
     694  	}
     695  	if (target && (rc = mnt_fs_set_target(self->fs, target))) {
     696  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     697  		return rc;
     698  	}
     699  	if (fstype && (rc = mnt_fs_set_fstype(self->fs, fstype))) {
     700  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     701  		return rc;
     702  	}
     703  	if (options && (rc = mnt_fs_set_options(self->fs, options))) {
     704  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     705  		return rc;
     706  	}
     707  	if (attributes && (rc = mnt_fs_set_attributes(self->fs, attributes))) {
     708  		PyErr_SetString(PyExc_MemoryError, MEMORY_ERR);
     709  		return rc;
     710  	}
     711  
     712  	mnt_fs_set_freq(self->fs, freq);
     713  	mnt_fs_set_passno(self->fs, passno);
     714  	mnt_fs_set_userdata(self->fs, self); /* store a pointer to self, convenient when resetting the table */
     715  	return 0;
     716  }
     717  
     718  /*
     719   * missing:
     720   * attribute
     721   * option
     722   */
     723  static PyGetSetDef Fs_getseters[] = {
     724  	{"id",		(getter)Fs_get_id, NULL, "mountinfo[1]: ID", NULL},
     725  	{"parent",	(getter)Fs_get_parent_id, NULL, "mountinfo[2]: parent", NULL},
     726  	{"devno",	(getter)Fs_get_devno, NULL, "mountinfo[3]: st_dev", NULL},
     727  	{"comment",	(getter)Fs_get_comment, (setter)Fs_set_comment, "fstab entry comment", NULL},
     728  	{"source",	(getter)Fs_get_source, (setter)Fs_set_source, "fstab[1], mountinfo[10], swaps[1]: source dev, file, dir or TAG", NULL},
     729  	{"srcpath",	(getter)Fs_get_srcpath, NULL, "mount source path or NULL in case of error or when the path is not defined.", NULL},
     730  	{"root",	(getter)Fs_get_root, (setter)Fs_set_root, "mountinfo[4]: root of the mount within the FS", NULL},
     731  	{"target",	(getter)Fs_get_target, (setter)Fs_set_target, "mountinfo[5], fstab[2]: mountpoint", NULL},
     732  	{"fstype",	(getter)Fs_get_fstype, (setter)Fs_set_fstype, "mountinfo[9], fstab[3]: filesystem type", NULL},
     733  	{"options",	(getter)Fs_get_options, (setter)Fs_set_options, "fstab[4]: merged options", NULL},
     734  	{"vfs_options",	(getter)Fs_get_vfs_options, NULL, "mountinfo[6]: fs-independent (VFS) options", NULL},
     735  	{"opt_fields",	(getter)Fs_get_optional_fields, NULL, "mountinfo[7]: optional fields", NULL},
     736  	{"fs_options",	(getter)Fs_get_fs_options, NULL, "mountinfo[11]: fs-dependent options", NULL},
     737  	{"usr_options",	(getter)Fs_get_user_options, NULL, "userspace mount options", NULL},
     738  	{"attributes",	(getter)Fs_get_attributes, (setter)Fs_set_attributes, "mount attributes", NULL},
     739  	{"freq",	(getter)Fs_get_freq, (setter)Fs_set_freq, "fstab[5]: dump frequency in days", NULL},
     740  	{"passno",	(getter)Fs_get_passno, (setter)Fs_set_passno, "fstab[6]: pass number on parallel fsck", NULL},
     741  	{"swaptype",	(getter)Fs_get_swaptype, NULL, "swaps[2]: device type", NULL},
     742  	{"size",	(getter)Fs_get_size, NULL, "saps[3]: swaparea size", NULL},
     743  	{"usedsize",	(getter)Fs_get_usedsize, NULL, "swaps[4]: used size", NULL},
     744  	{"priority",	(getter)Fs_get_priority, NULL, "swaps[5]: swap priority", NULL},
     745  	{"tag",		(getter)Fs_get_tag, NULL, "(Name, Value)", NULL},
     746  	{"tid",		(getter)Fs_get_tid, NULL, "/proc/<tid>/mountinfo, otherwise zero", NULL},
     747  	{NULL}
     748  };
     749  
     750  static PyObject *Fs_repr(FsObject *self)
     751  {
     752  	const char *src = mnt_fs_get_source(self->fs),
     753  		   *tgt = mnt_fs_get_target(self->fs),
     754  		   *type = mnt_fs_get_fstype(self->fs);
     755  
     756  	return PyUnicode_FromFormat(
     757  			"<libmount.Fs object at %p, "
     758  			"source=%s, target=%s, fstype=%s>",
     759  			self,
     760  			src ? src : "None",
     761  			tgt ? tgt : "None",
     762  			type ? type : "None");
     763  }
     764  
     765  PyObject *PyObjectResultFs(struct libmnt_fs *fs)
     766  {
     767  	FsObject *result;
     768  
     769  	if (!fs) {
     770  		PyErr_SetString(LibmountError, "internal exception");
     771  		return NULL;
     772  	}
     773  
     774  	result = mnt_fs_get_userdata(fs);
     775  	if (result) {
     776  		Py_INCREF(result);
     777  		DBG(FS, pymnt_debug_h(fs, "result py-obj %p: already exists, py-refcnt=%d",
     778  				result, (int) ((PyObject *) result)->ob_refcnt));
     779  		return (PyObject *) result;
     780  	}
     781  
     782  	/* Creating an encapsulating object: increment the refcount, so that code
     783  	 * such as tab.next_fs() doesn't call the destructor, which would free
     784  	 * our fs struct as well
     785  	 */
     786  	result = PyObject_New(FsObject, &FsType);
     787  	if (!result) {
     788  		UL_RaiseExc(ENOMEM);
     789  		return NULL;
     790  	}
     791  
     792  	Py_INCREF(result);
     793  	mnt_ref_fs(fs);
     794  
     795  	DBG(FS, pymnt_debug_h(fs, "result py-obj %p new, py-refcnt=%d",
     796  				result, (int) ((PyObject *) result)->ob_refcnt));
     797  	result->fs = fs;
     798  	mnt_fs_set_userdata(fs, result);
     799  	return (PyObject *) result;
     800  }
     801  
     802  static PyObject *Fs_copy_fs(FsObject *self, PyObject *args, PyObject *kwds)
     803  {
     804  	PyObject *dest = NULL;
     805  	char *kwlist[] = {"dest", NULL};
     806  
     807  	if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &dest)) {
     808  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     809  		return NULL;
     810  	}
     811  	if (PyObject_TypeCheck(dest, &FsType)) {	/* existing object passed as argument */
     812  		if (!mnt_copy_fs(((FsObject *)dest)->fs, self->fs))
     813  			return NULL;
     814  		DBG(FS, pymnt_debug_h(dest, "copy data"));
     815  		return (PyObject *)dest;
     816  
     817  	}
     818  
     819  	if (dest == Py_None) {			/* create new object */
     820  		FsObject *result = PyObject_New(FsObject, &FsType);
     821  
     822  		DBG(FS, pymnt_debug_h(result, "new copy"));
     823  		result->fs = mnt_copy_fs(NULL, self->fs);
     824  		mnt_fs_set_userdata(result->fs, result);	/* keep a pointer to encapsulating object */
     825  		return (PyObject *)result;
     826  	}
     827  
     828  	PyErr_SetString(PyExc_TypeError, ARG_ERR);
     829  	return NULL;
     830  }
     831  
     832  
     833  PyTypeObject FsType = {
     834  	PyVarObject_HEAD_INIT(NULL, 0)
     835  	"libmount.Fs", /*tp_name*/
     836  	sizeof(FsObject), /*tp_basicsize*/
     837  	0, /*tp_itemsize*/
     838  	(destructor)Fs_destructor, /*tp_dealloc*/
     839  	0, /*tp_print*/
     840  	NULL, /*tp_getattr*/
     841  	NULL, /*tp_setattr*/
     842  	NULL, /*tp_compare*/
     843  	(reprfunc)Fs_repr, /*tp_repr*/
     844  	NULL, /*tp_as_number*/
     845  	NULL, /*tp_as_sequence*/
     846  	NULL, /*tp_as_mapping*/
     847  	NULL, /*tp_hash */
     848  	NULL, /*tp_call*/
     849  	NULL, /*tp_str*/
     850  	NULL, /*tp_getattro*/
     851  	NULL, /*tp_setattro*/
     852  	NULL, /*tp_as_buffer*/
     853  	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
     854  	Fs_HELP, /* tp_doc */
     855  	NULL, /* tp_traverse */
     856  	NULL, /* tp_clear */
     857  	NULL, /* tp_richcompare */
     858  	0, /* tp_weaklistoffset */
     859  	NULL, /* tp_iter */
     860  	NULL, /* tp_iternext */
     861  	Fs_methods, /* tp_methods */
     862  	Fs_members, /* tp_members */
     863  	Fs_getseters, /* tp_getset */
     864  	NULL, /* tp_base */
     865  	NULL, /* tp_dict */
     866  	NULL, /* tp_descr_get */
     867  	NULL, /* tp_descr_set */
     868  	0, /* tp_dictoffset */
     869  	(initproc)Fs_init, /* tp_init */
     870  	NULL, /* tp_alloc */
     871  	Fs_new, /* tp_new */
     872  };
     873  
     874  void FS_AddModuleObject(PyObject *mod)
     875  {
     876  	if (PyType_Ready(&FsType) < 0)
     877  		return;
     878  
     879  	DBG(FS, pymnt_debug("add to module"));
     880  	Py_INCREF(&FsType);
     881  	PyModule_AddObject(mod, "Fs", (PyObject *)&FsType);
     882  }
     883