2 * Python bindings for the libmount library.
4 * Copyright (C) 2013, Red Hat, Inc. All rights reserved.
5 * Written by Ondrej Oprala and Karel Zak
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.
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.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://gnu.org/licenses/>.
20 #include "pylibmount.h"
22 /* Libmount-specific Exception class */
23 PyObject
*LibmountError
;
24 int pylibmount_debug_mask
;
26 PyObject
*UL_IncRef(void *killme
)
34 #if PY_MAJOR_VERSION >= 3
35 Py_TYPE(o
)->tp_free((PyObject
*)o
);
37 ((PyObject
*)o
)->ob_type
->tp_free((PyObject
*)o
);
41 /* Demultiplexer for various possible error conditions across the libmount library */
42 void *UL_RaiseExc(int e
)
44 /* TODO: Do we need to deal with -1/1? */
47 PyErr_SetString(PyExc_MemoryError
, strerror(e
));
50 PyErr_SetString(PyExc_TypeError
, strerror(e
));
52 /* libmount-specific errors */
54 PyErr_SetString(LibmountError
, "Not found required entry in fstab");
56 case MNT_ERR_NOFSTYPE
:
57 PyErr_SetString(LibmountError
, "Failed to detect filesystem type");
59 case MNT_ERR_NOSOURCE
:
60 PyErr_SetString(LibmountError
, "Required mount source undefined");
63 PyErr_SetString(LibmountError
, "Loopdev setup failed");
65 case MNT_ERR_APPLYFLAGS
:
66 PyErr_SetString(LibmountError
, "Failed to parse/use userspace mount options");
68 case MNT_ERR_MOUNTOPT
:
69 PyErr_SetString(LibmountError
, "Failed to apply propagation flags");
72 PyErr_SetString(LibmountError
, "Libblkid detected more filesystems on the device");
74 case MNT_ERR_LOOPOVERLAP
:
75 PyErr_SetString(LibmountError
, "Detected overlapping loop device that cannot be re-use");
78 PyErr_SetString(LibmountError
, "Failed to lock mtab/utab or so");
80 case MNT_ERR_NAMESPACE
:
81 PyErr_SetString(LibmountError
, "Failed to switch namespace");
83 /* some other errno */
85 PyErr_SetString(PyExc_Exception
, strerror(e
));
94 PyObject
*PyObjectResultInt(int i
)
96 PyObject
*result
= Py_BuildValue("i", i
);
98 PyErr_SetString(PyExc_RuntimeError
, CONSTRUCT_ERR
);
102 PyObject
*PyObjectResultStr(const char *s
)
106 /* TODO: maybe lie about it and return "":
107 * which would allow for
109 * fs.comment += "comment"
110 return Py_BuildValue("s", ""); */
112 result
= Py_BuildValue("s", s
);
114 PyErr_SetString(PyExc_RuntimeError
, CONSTRUCT_ERR
);
118 /* wrapper around a common use case for PyUnicode_AsASCIIString() */
119 char *pystos(PyObject
*pys
)
121 #if PY_MAJOR_VERSION >= 3
122 if (!PyUnicode_Check(pys
)) {
123 PyErr_SetString(PyExc_TypeError
, ARG_ERR
);
126 return (char *)PyUnicode_1BYTE_DATA(pys
);
128 if (!PyString_Check(pys
)) {
129 PyErr_SetString(PyExc_TypeError
, ARG_ERR
);
132 return PyString_AsString(pys
);
137 * the libmount module
139 #define PYLIBMOUNT_DESC \
140 "Python API for the util-linux libmount library.\n\n" \
141 "Please note that none of the classes' attributes may be deleted.\n" \
142 "This is not a complete mapping to the libmount C API, nor is it\n" \
143 "attempting to be one.\n" "Iterator functions only allow forward\n" \
144 "iteration for now. Context.get_{user_,}mflags() differs from the C API\n" \
145 "and returns the flags directly. Fs.get_tag() differs from the C API\n" \
146 "and returns a (tag, value) tuple. Every attribute is \"filtered\"" \
147 "through appropriate getters/setters, no values are set directly."
150 struct module_state
{
154 #if PY_MAJOR_VERSION >= 3
155 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
157 #define GETSTATE(m) (&_state)
158 static struct module_state _state
;
162 error_out(PyObject
*m
__attribute__((unused
))) {
163 struct module_state
*st
= GETSTATE(m
);
164 PyErr_SetString(st
->error
, "something bad happened");
168 static PyMethodDef pylibmount_methods
[] = {
169 {"error_out", (PyCFunction
)error_out
, METH_NOARGS
, NULL
},
173 #if PY_MAJOR_VERSION >= 3
175 static int pylibmount_traverse(PyObject
*m
, visitproc visit
, void *arg
) {
176 Py_VISIT(GETSTATE(m
)->error
);
180 static int pylibmount_clear(PyObject
*m
) {
181 Py_CLEAR(GETSTATE(m
)->error
);
185 static struct PyModuleDef moduledef
= {
186 PyModuleDef_HEAD_INIT
,
189 sizeof(struct module_state
),
196 #define INITERROR return NULL
197 PyMODINIT_FUNC
PyInit_pylibmount(void);
198 PyMODINIT_FUNC
PyInit_pylibmount(void)
200 #define INITERROR return
201 # ifndef PyMODINIT_FUNC
202 # define PyMODINIT_FUNC void
204 PyMODINIT_FUNC
initpylibmount(void);
205 PyMODINIT_FUNC
initpylibmount(void)
208 #if PY_MAJOR_VERSION >= 3
209 PyObject
*m
= PyModule_Create(&moduledef
);
211 PyObject
*m
= Py_InitModule3("pylibmount", pylibmount_methods
, PYLIBMOUNT_DESC
);
219 if (!(pylibmount_debug_mask
& PYMNT_DEBUG_INIT
)) {
220 char *str
= getenv("PYLIBMOUNT_DEBUG");
223 pylibmount_debug_mask
= 0;
225 pylibmount_debug_mask
= strtoul(str
, NULL
, 0);
227 pylibmount_debug_mask
= 0;
229 pylibmount_debug_mask
|= PYMNT_DEBUG_INIT
;
232 if (pylibmount_debug_mask
&& pylibmount_debug_mask
!= PYMNT_DEBUG_INIT
)
233 DBG(INIT
, pymnt_debug("library debug mask: 0x%04x",
234 pylibmount_debug_mask
));
240 LibmountError
= PyErr_NewException("libmount.Error", NULL
, NULL
);
241 Py_INCREF(LibmountError
);
242 PyModule_AddObject(m
, "Error", (PyObject
*)LibmountError
);
244 FS_AddModuleObject(m
);
245 Table_AddModuleObject(m
);
247 Context_AddModuleObject(m
);
251 * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
253 PyModule_AddIntConstant(m
, "MNT_MS_COMMENT", MNT_MS_COMMENT
);
254 PyModule_AddIntConstant(m
, "MNT_MS_GROUP", MNT_MS_GROUP
);
255 PyModule_AddIntConstant(m
, "MNT_MS_HELPER", MNT_MS_HELPER
);
256 PyModule_AddIntConstant(m
, "MNT_MS_LOOP", MNT_MS_LOOP
);
257 PyModule_AddIntConstant(m
, "MNT_MS_NETDEV", MNT_MS_NETDEV
);
258 PyModule_AddIntConstant(m
, "MNT_MS_NOAUTO", MNT_MS_NOAUTO
);
259 PyModule_AddIntConstant(m
, "MNT_MS_NOFAIL", MNT_MS_NOFAIL
);
260 PyModule_AddIntConstant(m
, "MNT_MS_OFFSET", MNT_MS_OFFSET
);
261 PyModule_AddIntConstant(m
, "MNT_MS_OWNER", MNT_MS_OWNER
);
262 PyModule_AddIntConstant(m
, "MNT_MS_SIZELIMIT", MNT_MS_SIZELIMIT
);
263 PyModule_AddIntConstant(m
, "MNT_MS_ENCRYPTION", MNT_MS_ENCRYPTION
);
264 PyModule_AddIntConstant(m
, "MNT_MS_UHELPER", MNT_MS_UHELPER
);
265 PyModule_AddIntConstant(m
, "MNT_MS_USER", MNT_MS_USER
);
266 PyModule_AddIntConstant(m
, "MNT_MS_USERS", MNT_MS_USERS
);
267 PyModule_AddIntConstant(m
, "MNT_MS_XCOMMENT", MNT_MS_XCOMMENT
);
268 PyModule_AddIntConstant(m
, "MNT_MS_HASH_DEVICE", MNT_MS_HASH_DEVICE
);
269 PyModule_AddIntConstant(m
, "MNT_MS_ROOT_HASH", MNT_MS_ROOT_HASH
);
270 PyModule_AddIntConstant(m
, "MNT_MS_HASH_OFFSET", MNT_MS_HASH_OFFSET
);
271 PyModule_AddIntConstant(m
, "MNT_MS_ROOT_HASH_FILE", MNT_MS_ROOT_HASH_FILE
);
272 PyModule_AddIntConstant(m
, "MNT_MS_FEC_DEVICE", MNT_MS_FEC_DEVICE
);
273 PyModule_AddIntConstant(m
, "MNT_MS_FEC_OFFSET", MNT_MS_FEC_OFFSET
);
274 PyModule_AddIntConstant(m
, "MNT_MS_FEC_ROOTS", MNT_MS_FEC_ROOTS
);
275 PyModule_AddIntConstant(m
, "MNT_MS_ROOT_HASH_SIG", MNT_MS_ROOT_HASH_SIG
);
278 * mount(2) MS_* masks (MNT_MAP_LINUX map)
280 PyModule_AddIntConstant(m
, "MS_BIND", MS_BIND
);
281 PyModule_AddIntConstant(m
, "MS_DIRSYNC", MS_DIRSYNC
);
282 PyModule_AddIntConstant(m
, "MS_I_VERSION", MS_I_VERSION
);
283 PyModule_AddIntConstant(m
, "MS_MANDLOCK", MS_MANDLOCK
);
284 PyModule_AddIntConstant(m
, "MS_MGC_MSK", MS_MGC_MSK
);
285 PyModule_AddIntConstant(m
, "MS_MGC_VAL", MS_MGC_VAL
);
286 PyModule_AddIntConstant(m
, "MS_MOVE", MS_MOVE
);
287 PyModule_AddIntConstant(m
, "MS_NOATIME", MS_NOATIME
);
288 PyModule_AddIntConstant(m
, "MS_NODEV", MS_NODEV
);
289 PyModule_AddIntConstant(m
, "MS_NODIRATIME", MS_NODIRATIME
);
290 PyModule_AddIntConstant(m
, "MS_NOEXEC", MS_NOEXEC
);
291 PyModule_AddIntConstant(m
, "MS_NOSUID", MS_NOSUID
);
292 PyModule_AddIntConstant(m
, "MS_OWNERSECURE", MS_OWNERSECURE
);
293 PyModule_AddIntConstant(m
, "MS_PRIVATE", MS_PRIVATE
);
294 PyModule_AddIntConstant(m
, "MS_PROPAGATION", MS_PROPAGATION
);
295 PyModule_AddIntConstant(m
, "MS_RDONLY", MS_RDONLY
);
296 PyModule_AddIntConstant(m
, "MS_REC", MS_REC
);
297 PyModule_AddIntConstant(m
, "MS_RELATIME", MS_RELATIME
);
298 PyModule_AddIntConstant(m
, "MS_REMOUNT", MS_REMOUNT
);
299 PyModule_AddIntConstant(m
, "MS_SECURE", MS_SECURE
);
300 PyModule_AddIntConstant(m
, "MS_SHARED", MS_SHARED
);
301 PyModule_AddIntConstant(m
, "MS_SILENT", MS_SILENT
);
302 PyModule_AddIntConstant(m
, "MS_SLAVE", MS_SLAVE
);
303 PyModule_AddIntConstant(m
, "MS_STRICTATIME", MS_STRICTATIME
);
304 PyModule_AddIntConstant(m
, "MS_SYNCHRONOUS", MS_SYNCHRONOUS
);
305 PyModule_AddIntConstant(m
, "MS_UNBINDABLE", MS_UNBINDABLE
);
307 /* Will we need these directly?
308 PyModule_AddIntConstant(m, "MNT_ERR_AMBIFS", MNT_ERR_AMBIFS);
309 PyModule_AddIntConstant(m, "MNT_ERR_APPLYFLAGS", MNT_ERR_APPLYFLAGS);
310 PyModule_AddIntConstant(m, "MNT_ERR_LOOPDEV", MNT_ERR_LOOPDEV);
311 PyModule_AddIntConstant(m, "MNT_ERR_MOUNTOPT", MNT_ERR_MOUNTOPT);
312 PyModule_AddIntConstant(m, "MNT_ERR_NOFSTAB", MNT_ERR_NOFSTAB);
313 PyModule_AddIntConstant(m, "MNT_ERR_NOFSTYPE", MNT_ERR_NOFSTYPE);
314 PyModule_AddIntConstant(m, "MNT_ERR_NOSOURCE", MNT_ERR_NOSOURCE);
317 /* Still useful for functions using iterators internally */
318 PyModule_AddIntConstant(m
, "MNT_ITER_FORWARD", MNT_ITER_FORWARD
);
319 PyModule_AddIntConstant(m
, "MNT_ITER_BACKWARD", MNT_ITER_BACKWARD
);
321 #if PY_MAJOR_VERSION >= 3