(root)/
util-linux-2.39/
libmount/
python/
pylibmount.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  #include "pylibmount.h"
      22  
      23  /* Libmount-specific Exception class */
      24  PyObject *LibmountError;
      25  int pylibmount_debug_mask;
      26  
      27  PyObject *UL_IncRef(void *killme)
      28  {
      29  	Py_INCREF(killme);
      30  	return killme;
      31  }
      32  
      33  void PyFree(void *o)
      34  {
      35  #if PY_MAJOR_VERSION >= 3
      36  	Py_TYPE(o)->tp_free((PyObject *)o);
      37  #else
      38  	((PyObject *)o)->ob_type->tp_free((PyObject *)o);
      39  #endif
      40  }
      41  
      42  /* Demultiplexer for various possible error conditions across the libmount library */
      43  void *UL_RaiseExc(int e)
      44  {
      45  	/* TODO: Do we need to deal with -1/1? */
      46  	switch (e) {
      47  		case ENOMEM:
      48  			PyErr_SetString(PyExc_MemoryError, strerror(e));
      49  			break;
      50  		case EINVAL:
      51  			PyErr_SetString(PyExc_TypeError, strerror(e));
      52  			break;
      53  		/* libmount-specific errors */
      54  		case MNT_ERR_NOFSTAB:
      55  			PyErr_SetString(LibmountError, "Not found required entry in fstab");
      56  			break;
      57  		case MNT_ERR_NOFSTYPE:
      58  			PyErr_SetString(LibmountError, "Lailed to detect filesystem type");
      59  			break;
      60  		case MNT_ERR_NOSOURCE:
      61  			PyErr_SetString(LibmountError, "Required mount source undefined");
      62  			break;
      63  		case MNT_ERR_LOOPDEV:
      64  			PyErr_SetString(LibmountError, "Loopdev setup failed");
      65  			break;
      66  		case MNT_ERR_APPLYFLAGS:
      67  			PyErr_SetString(LibmountError, "Failed to parse/use userspace mount options");
      68  			break;
      69  		case MNT_ERR_MOUNTOPT:
      70  			PyErr_SetString(LibmountError, "Failed to apply propagation flags");
      71  			break;
      72  		case MNT_ERR_AMBIFS:
      73  			PyErr_SetString(LibmountError, "Libblkid detected more filesystems on the device");
      74  			break;
      75  		case MNT_ERR_LOOPOVERLAP:
      76  			PyErr_SetString(LibmountError, "Detected overlapping loop device that cannot be re-use");
      77  			break;
      78  		case MNT_ERR_LOCK:
      79  			PyErr_SetString(LibmountError, "Failed to lock mtab/utab or so");
      80  			break;
      81  		case MNT_ERR_NAMESPACE:
      82  			PyErr_SetString(LibmountError, "Failed to switch namespace");
      83  			break;
      84  		/* some other errno */
      85  		default:
      86  			PyErr_SetString(PyExc_Exception, strerror(e));
      87  			break;
      88  	}
      89  	return NULL;
      90  }
      91  
      92  /*
      93   * General functions
      94   */
      95  PyObject *PyObjectResultInt(int i)
      96  {
      97  	PyObject *result = Py_BuildValue("i", i);
      98  	if (!result)
      99  		PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
     100  	return result;
     101  }
     102  
     103  PyObject *PyObjectResultStr(const char *s)
     104  {
     105  	PyObject *result;
     106  	if (!s)
     107  		/* TODO: maybe lie about it and return "":
     108  		 * which would allow for
     109  		 * fs = libmount.Fs()
     110  		 * fs.comment += "comment"
     111  		return Py_BuildValue("s", ""); */
     112  		Py_RETURN_NONE;
     113  	result = Py_BuildValue("s", s);
     114  	if (!result)
     115  		PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
     116  	return result;
     117  }
     118  
     119  /* wrapper around a common use case for PyUnicode_AsASCIIString() */
     120  char *pystos(PyObject *pys)
     121  {
     122  #if PY_MAJOR_VERSION >= 3
     123  	if (!PyUnicode_Check(pys)) {
     124  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     125  		return NULL;
     126  	}
     127  	return (char *)PyUnicode_1BYTE_DATA(pys);
     128  #else
     129  	if (!PyString_Check(pys)) {
     130  		PyErr_SetString(PyExc_TypeError, ARG_ERR);
     131  		return NULL;
     132  	}
     133  	return PyString_AsString(pys);
     134  #endif
     135  }
     136  
     137  /*
     138   * the libmount module
     139   */
     140  #define PYLIBMOUNT_DESC \
     141  	"Python API for the util-linux libmount library.\n\n" \
     142  	"Please note that none of the classes' attributes may be deleted.\n" \
     143  	"This is not a complete mapping to the libmount C API, nor is it\n" \
     144  	"attempting to be one.\n" "Iterator functions only allow forward\n" \
     145  	"iteration for now. Context.get_{user_,}mflags() differs from the C API\n" \
     146  	"and returns the flags directly. Fs.get_tag() differs from the C API\n" \
     147  	"and returns a (tag, value) tuple. Every attribute is \"filtered\"" \
     148  	"through appropriate getters/setters, no values are set directly."
     149  
     150  
     151  struct module_state {
     152      PyObject *error;
     153  };
     154  
     155  #if PY_MAJOR_VERSION >= 3
     156  #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
     157  #else
     158  #define GETSTATE(m) (&_state)
     159  static struct module_state _state;
     160  #endif
     161  
     162  static PyObject *
     163  error_out(PyObject *m __attribute__((unused))) {
     164      struct module_state *st = GETSTATE(m);
     165      PyErr_SetString(st->error, "something bad happened");
     166      return NULL;
     167  }
     168  
     169  static PyMethodDef pylibmount_methods[] = {
     170      {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
     171      {NULL, NULL}
     172  };
     173  
     174  #if PY_MAJOR_VERSION >= 3
     175  
     176  static int pylibmount_traverse(PyObject *m, visitproc visit, void *arg) {
     177      Py_VISIT(GETSTATE(m)->error);
     178      return 0;
     179  }
     180  
     181  static int pylibmount_clear(PyObject *m) {
     182      Py_CLEAR(GETSTATE(m)->error);
     183      return 0;
     184  }
     185  
     186  static struct PyModuleDef moduledef = {
     187          PyModuleDef_HEAD_INIT,
     188          "pylibmount",
     189          NULL,
     190          sizeof(struct module_state),
     191          pylibmount_methods,
     192          NULL,
     193          pylibmount_traverse,
     194          pylibmount_clear,
     195          NULL
     196  };
     197  #define INITERROR return NULL
     198  PyMODINIT_FUNC PyInit_pylibmount(void);
     199  PyMODINIT_FUNC PyInit_pylibmount(void)
     200  #else
     201  #define INITERROR return
     202  # ifndef PyMODINIT_FUNC
     203  #  define PyMODINIT_FUNC void
     204  # endif
     205  PyMODINIT_FUNC initpylibmount(void);
     206  PyMODINIT_FUNC initpylibmount(void)
     207  #endif
     208  {
     209  #if PY_MAJOR_VERSION >= 3
     210  	PyObject *m = PyModule_Create(&moduledef);
     211  #else
     212  	PyObject *m = Py_InitModule3("pylibmount", pylibmount_methods, PYLIBMOUNT_DESC);
     213  #endif
     214  
     215  	if (!m)
     216  		INITERROR;
     217  	/*
     218  	 * init debug stuff
     219  	 */
     220  	if (!(pylibmount_debug_mask & PYMNT_DEBUG_INIT)) {
     221  		char *str = getenv("PYLIBMOUNT_DEBUG");
     222  
     223  		errno = 0;
     224  		pylibmount_debug_mask = 0;
     225  		if (str)
     226  			pylibmount_debug_mask = strtoul(str, NULL, 0);
     227  		if (errno)
     228  			pylibmount_debug_mask = 0;
     229  
     230  		pylibmount_debug_mask |= PYMNT_DEBUG_INIT;
     231  	}
     232  
     233  	if (pylibmount_debug_mask && pylibmount_debug_mask != PYMNT_DEBUG_INIT)
     234  		DBG(INIT, pymnt_debug("library debug mask: 0x%04x",
     235  					pylibmount_debug_mask));
     236  	mnt_init_debug(0);
     237  
     238  	/*
     239  	 * Add module objects
     240  	 */
     241  	LibmountError = PyErr_NewException("libmount.Error", NULL, NULL);
     242  	Py_INCREF(LibmountError);
     243  	PyModule_AddObject(m, "Error", (PyObject *)LibmountError);
     244  
     245  	FS_AddModuleObject(m);
     246  	Table_AddModuleObject(m);
     247  #ifdef __linux__
     248  	Context_AddModuleObject(m);
     249  #endif
     250  
     251  	/*
     252  	 * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
     253  	 */
     254  	PyModule_AddIntConstant(m, "MNT_MS_COMMENT", MNT_MS_COMMENT);
     255  	PyModule_AddIntConstant(m, "MNT_MS_GROUP", MNT_MS_GROUP);
     256  	PyModule_AddIntConstant(m, "MNT_MS_HELPER", MNT_MS_HELPER);
     257  	PyModule_AddIntConstant(m, "MNT_MS_LOOP", MNT_MS_LOOP);
     258  	PyModule_AddIntConstant(m, "MNT_MS_NETDEV", MNT_MS_NETDEV);
     259  	PyModule_AddIntConstant(m, "MNT_MS_NOAUTO", MNT_MS_NOAUTO);
     260  	PyModule_AddIntConstant(m, "MNT_MS_NOFAIL", MNT_MS_NOFAIL);
     261  	PyModule_AddIntConstant(m, "MNT_MS_OFFSET", MNT_MS_OFFSET);
     262  	PyModule_AddIntConstant(m, "MNT_MS_OWNER", MNT_MS_OWNER);
     263  	PyModule_AddIntConstant(m, "MNT_MS_SIZELIMIT", MNT_MS_SIZELIMIT);
     264  	PyModule_AddIntConstant(m, "MNT_MS_ENCRYPTION", MNT_MS_ENCRYPTION);
     265  	PyModule_AddIntConstant(m, "MNT_MS_UHELPER", MNT_MS_UHELPER);
     266  	PyModule_AddIntConstant(m, "MNT_MS_USER", MNT_MS_USER);
     267  	PyModule_AddIntConstant(m, "MNT_MS_USERS", MNT_MS_USERS);
     268  	PyModule_AddIntConstant(m, "MNT_MS_XCOMMENT", MNT_MS_XCOMMENT);
     269  	PyModule_AddIntConstant(m, "MNT_MS_HASH_DEVICE", MNT_MS_HASH_DEVICE);
     270  	PyModule_AddIntConstant(m, "MNT_MS_ROOT_HASH", MNT_MS_ROOT_HASH);
     271  	PyModule_AddIntConstant(m, "MNT_MS_HASH_OFFSET", MNT_MS_HASH_OFFSET);
     272  	PyModule_AddIntConstant(m, "MNT_MS_ROOT_HASH_FILE", MNT_MS_ROOT_HASH_FILE);
     273  	PyModule_AddIntConstant(m, "MNT_MS_FEC_DEVICE", MNT_MS_FEC_DEVICE);
     274  	PyModule_AddIntConstant(m, "MNT_MS_FEC_OFFSET", MNT_MS_FEC_OFFSET);
     275  	PyModule_AddIntConstant(m, "MNT_MS_FEC_ROOTS", MNT_MS_FEC_ROOTS);
     276  	PyModule_AddIntConstant(m, "MNT_MS_ROOT_HASH_SIG", MNT_MS_ROOT_HASH_SIG);
     277  
     278  	/*
     279  	 * mount(2) MS_* masks (MNT_MAP_LINUX map)
     280  	 */
     281  	PyModule_AddIntConstant(m, "MS_BIND", MS_BIND);
     282  	PyModule_AddIntConstant(m, "MS_DIRSYNC", MS_DIRSYNC);
     283  	PyModule_AddIntConstant(m, "MS_I_VERSION", MS_I_VERSION);
     284  	PyModule_AddIntConstant(m, "MS_MANDLOCK", MS_MANDLOCK);
     285  	PyModule_AddIntConstant(m, "MS_MGC_MSK", MS_MGC_MSK);
     286  	PyModule_AddIntConstant(m, "MS_MGC_VAL", MS_MGC_VAL);
     287  	PyModule_AddIntConstant(m, "MS_MOVE", MS_MOVE);
     288  	PyModule_AddIntConstant(m, "MS_NOATIME", MS_NOATIME);
     289  	PyModule_AddIntConstant(m, "MS_NODEV", MS_NODEV);
     290  	PyModule_AddIntConstant(m, "MS_NODIRATIME", MS_NODIRATIME);
     291  	PyModule_AddIntConstant(m, "MS_NOEXEC", MS_NOEXEC);
     292  	PyModule_AddIntConstant(m, "MS_NOSUID", MS_NOSUID);
     293  	PyModule_AddIntConstant(m, "MS_OWNERSECURE", MS_OWNERSECURE);
     294  	PyModule_AddIntConstant(m, "MS_PRIVATE", MS_PRIVATE);
     295  	PyModule_AddIntConstant(m, "MS_PROPAGATION", MS_PROPAGATION);
     296  	PyModule_AddIntConstant(m, "MS_RDONLY", MS_RDONLY);
     297  	PyModule_AddIntConstant(m, "MS_REC", MS_REC);
     298  	PyModule_AddIntConstant(m, "MS_RELATIME", MS_RELATIME);
     299  	PyModule_AddIntConstant(m, "MS_REMOUNT", MS_REMOUNT);
     300  	PyModule_AddIntConstant(m, "MS_SECURE", MS_SECURE);
     301  	PyModule_AddIntConstant(m, "MS_SHARED", MS_SHARED);
     302  	PyModule_AddIntConstant(m, "MS_SILENT", MS_SILENT);
     303  	PyModule_AddIntConstant(m, "MS_SLAVE", MS_SLAVE);
     304  	PyModule_AddIntConstant(m, "MS_STRICTATIME", MS_STRICTATIME);
     305  	PyModule_AddIntConstant(m, "MS_SYNCHRONOUS", MS_SYNCHRONOUS);
     306  	PyModule_AddIntConstant(m, "MS_UNBINDABLE", MS_UNBINDABLE);
     307  
     308  	/* Will we need these directly?
     309  	PyModule_AddIntConstant(m, "MNT_ERR_AMBIFS", MNT_ERR_AMBIFS);
     310  	PyModule_AddIntConstant(m, "MNT_ERR_APPLYFLAGS", MNT_ERR_APPLYFLAGS);
     311  	PyModule_AddIntConstant(m, "MNT_ERR_LOOPDEV", MNT_ERR_LOOPDEV);
     312  	PyModule_AddIntConstant(m, "MNT_ERR_MOUNTOPT", MNT_ERR_MOUNTOPT);
     313  	PyModule_AddIntConstant(m, "MNT_ERR_NOFSTAB", MNT_ERR_NOFSTAB);
     314  	PyModule_AddIntConstant(m, "MNT_ERR_NOFSTYPE", MNT_ERR_NOFSTYPE);
     315  	PyModule_AddIntConstant(m, "MNT_ERR_NOSOURCE", MNT_ERR_NOSOURCE);
     316  	*/
     317  
     318  	/* Still useful for functions using iterators internally */
     319  	PyModule_AddIntConstant(m, "MNT_ITER_FORWARD", MNT_ITER_FORWARD);
     320  	PyModule_AddIntConstant(m, "MNT_ITER_BACKWARD", MNT_ITER_BACKWARD);
     321  
     322  #if PY_MAJOR_VERSION >= 3
     323  	return m;
     324  #endif
     325  }
     326