]> git.ipfire.org Git - thirdparty/util-linux.git/blame_incremental - libmount/python/pylibmount.c
lib/path: avoid double free() for cpusets
[thirdparty/util-linux.git] / libmount / python / pylibmount.c
... / ...
CommitLineData
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 */
23PyObject *LibmountError;
24int pylibmount_debug_mask;
25
26PyObject *UL_IncRef(void *killme)
27{
28 Py_INCREF(killme);
29 return killme;
30}
31
32void 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 */
42void *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 */
94PyObject *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
102PyObject *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() */
119char *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
150struct 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)
158static struct module_state _state;
159#endif
160
161static PyObject *
162error_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
168static PyMethodDef pylibmount_methods[] = {
169 {"error_out", (PyCFunction)error_out, METH_NOARGS, NULL},
170 {NULL, NULL}
171};
172
173#if PY_MAJOR_VERSION >= 3
174
175static int pylibmount_traverse(PyObject *m, visitproc visit, void *arg) {
176 Py_VISIT(GETSTATE(m)->error);
177 return 0;
178}
179
180static int pylibmount_clear(PyObject *m) {
181 Py_CLEAR(GETSTATE(m)->error);
182 return 0;
183}
184
185static 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
197PyMODINIT_FUNC PyInit_pylibmount(void);
198PyMODINIT_FUNC PyInit_pylibmount(void)
199#else
200#define INITERROR return
201# ifndef PyMODINIT_FUNC
202# define PyMODINIT_FUNC void
203# endif
204PyMODINIT_FUNC initpylibmount(void);
205PyMODINIT_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