]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/python/pylibmount.c
e8c191602aa9c9b6024bd1d21b89f892aabfa764
[thirdparty/util-linux.git] / 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 General Public License
18 * along with this program. If not, see <https://gnu.org/licenses/>.
19 */
20 #include "pylibmount.h"
21
22 /* Libmount-specific Exception class */
23 PyObject *LibmountError;
24 int pylibmount_debug_mask;
25
26 PyObject *UL_IncRef(void *killme)
27 {
28 Py_INCREF(killme);
29 return killme;
30 }
31
32 void PyFree(void *o)
33 {
34 #if PY_MAJOR_VERSION >= 3
35 Py_TYPE(o)->tp_free((PyObject *)o);
36 #else
37 ((PyObject *)o)->ob_type->tp_free((PyObject *)o);
38 #endif
39 }
40
41 /* Demultiplexer for various possible error conditions across the libmount library */
42 void *UL_RaiseExc(int e)
43 {
44 /* TODO: Do we need to deal with -1/1? */
45 switch (e) {
46 case ENOMEM:
47 PyErr_SetString(PyExc_MemoryError, strerror(e));
48 break;
49 case EINVAL:
50 PyErr_SetString(PyExc_TypeError, strerror(e));
51 break;
52 /* libmount-specific errors */
53 case MNT_ERR_NOFSTAB:
54 PyErr_SetString(LibmountError, "Not found required entry in fstab");
55 break;
56 case MNT_ERR_NOFSTYPE:
57 PyErr_SetString(LibmountError, "Failed to detect filesystem type");
58 break;
59 case MNT_ERR_NOSOURCE:
60 PyErr_SetString(LibmountError, "Required mount source undefined");
61 break;
62 case MNT_ERR_LOOPDEV:
63 PyErr_SetString(LibmountError, "Loopdev setup failed");
64 break;
65 case MNT_ERR_APPLYFLAGS:
66 PyErr_SetString(LibmountError, "Failed to parse/use userspace mount options");
67 break;
68 case MNT_ERR_MOUNTOPT:
69 PyErr_SetString(LibmountError, "Failed to apply propagation flags");
70 break;
71 case MNT_ERR_AMBIFS:
72 PyErr_SetString(LibmountError, "Libblkid detected more filesystems on the device");
73 break;
74 case MNT_ERR_LOOPOVERLAP:
75 PyErr_SetString(LibmountError, "Detected overlapping loop device that cannot be re-use");
76 break;
77 case MNT_ERR_LOCK:
78 PyErr_SetString(LibmountError, "Failed to lock mtab/utab or so");
79 break;
80 case MNT_ERR_NAMESPACE:
81 PyErr_SetString(LibmountError, "Failed to switch namespace");
82 break;
83 /* some other errno */
84 default:
85 PyErr_SetString(PyExc_Exception, strerror(e));
86 break;
87 }
88 return NULL;
89 }
90
91 /*
92 * General functions
93 */
94 PyObject *PyObjectResultInt(int i)
95 {
96 PyObject *result = Py_BuildValue("i", i);
97 if (!result)
98 PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
99 return result;
100 }
101
102 PyObject *PyObjectResultStr(const char *s)
103 {
104 PyObject *result;
105 if (!s)
106 /* TODO: maybe lie about it and return "":
107 * which would allow for
108 * fs = libmount.Fs()
109 * fs.comment += "comment"
110 return Py_BuildValue("s", ""); */
111 Py_RETURN_NONE;
112 result = Py_BuildValue("s", s);
113 if (!result)
114 PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
115 return result;
116 }
117
118 /* wrapper around a common use case for PyUnicode_AsASCIIString() */
119 char *pystos(PyObject *pys)
120 {
121 #if PY_MAJOR_VERSION >= 3
122 if (!PyUnicode_Check(pys)) {
123 PyErr_SetString(PyExc_TypeError, ARG_ERR);
124 return NULL;
125 }
126 return (char *)PyUnicode_1BYTE_DATA(pys);
127 #else
128 if (!PyString_Check(pys)) {
129 PyErr_SetString(PyExc_TypeError, ARG_ERR);
130 return NULL;
131 }
132 return PyString_AsString(pys);
133 #endif
134 }
135
136 /*
137 * the libmount module
138 */
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."
148
149
150 struct module_state {
151 PyObject *error;
152 };
153
154 #if PY_MAJOR_VERSION >= 3
155 #define GETSTATE(m) ((struct module_state*)PyModule_GetState(m))
156 #else
157 #define GETSTATE(m) (&_state)
158 static struct module_state _state;
159 #endif
160
161 static PyObject *
162 error_out(PyObject *m __attribute__((unused))) {
163 struct module_state *st = GETSTATE(m);
164 PyErr_SetString(st->error, "something bad happened");
165 return NULL;
166 }
167
168 static PyMethodDef pylibmount_methods[] = {
169 {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
170 {NULL, NULL}
171 };
172
173 #if PY_MAJOR_VERSION >= 3
174
175 static int pylibmount_traverse(PyObject *m, visitproc visit, void *arg) {
176 Py_VISIT(GETSTATE(m)->error);
177 return 0;
178 }
179
180 static int pylibmount_clear(PyObject *m) {
181 Py_CLEAR(GETSTATE(m)->error);
182 return 0;
183 }
184
185 static struct PyModuleDef moduledef = {
186 PyModuleDef_HEAD_INIT,
187 "pylibmount",
188 NULL,
189 sizeof(struct module_state),
190 pylibmount_methods,
191 NULL,
192 pylibmount_traverse,
193 pylibmount_clear,
194 NULL
195 };
196 #define INITERROR return NULL
197 PyMODINIT_FUNC PyInit_pylibmount(void);
198 PyMODINIT_FUNC PyInit_pylibmount(void)
199 #else
200 #define INITERROR return
201 # ifndef PyMODINIT_FUNC
202 # define PyMODINIT_FUNC void
203 # endif
204 PyMODINIT_FUNC initpylibmount(void);
205 PyMODINIT_FUNC initpylibmount(void)
206 #endif
207 {
208 #if PY_MAJOR_VERSION >= 3
209 PyObject *m = PyModule_Create(&moduledef);
210 #else
211 PyObject *m = Py_InitModule3("pylibmount", pylibmount_methods, PYLIBMOUNT_DESC);
212 #endif
213
214 if (!m)
215 INITERROR;
216 /*
217 * init debug stuff
218 */
219 if (!(pylibmount_debug_mask & PYMNT_DEBUG_INIT)) {
220 char *str = getenv("PYLIBMOUNT_DEBUG");
221
222 errno = 0;
223 pylibmount_debug_mask = 0;
224 if (str)
225 pylibmount_debug_mask = strtoul(str, NULL, 0);
226 if (errno)
227 pylibmount_debug_mask = 0;
228
229 pylibmount_debug_mask |= PYMNT_DEBUG_INIT;
230 }
231
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));
235 mnt_init_debug(0);
236
237 /*
238 * Add module objects
239 */
240 LibmountError = PyErr_NewException("libmount.Error", NULL, NULL);
241 Py_INCREF(LibmountError);
242 PyModule_AddObject(m, "Error", (PyObject *)LibmountError);
243
244 FS_AddModuleObject(m);
245 Table_AddModuleObject(m);
246 #ifdef __linux__
247 Context_AddModuleObject(m);
248 #endif
249
250 /*
251 * mount(8) userspace options masks (MNT_MAP_USERSPACE map)
252 */
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);
276
277 /*
278 * mount(2) MS_* masks (MNT_MAP_LINUX map)
279 */
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);
306
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);
315 */
316
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);
320
321 #if PY_MAJOR_VERSION >= 3
322 return m;
323 #endif
324 }
325