]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/python/pylibmount.c
more: Use ul_strtou16() in a robust way
[thirdparty/util-linux.git] / libmount / python / pylibmount.c
CommitLineData
813683a3
OO
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 *
762f295a
BS
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/>.
813683a3
OO
19 */
20#include "pylibmount.h"
21
22/* Libmount-specific Exception class */
23PyObject *LibmountError;
b7e47ac1
KZ
24int pylibmount_debug_mask;
25
813683a3
OO
26PyObject *UL_IncRef(void *killme)
27{
28 Py_INCREF(killme);
29 return killme;
30}
31
46407453
OO
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
813683a3
OO
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 */
813683a3 53 case MNT_ERR_NOFSTAB:
e2aedec8 54 PyErr_SetString(LibmountError, "Not found required entry in fstab");
813683a3
OO
55 break;
56 case MNT_ERR_NOFSTYPE:
5225bdad 57 PyErr_SetString(LibmountError, "Failed to detect filesystem type");
813683a3
OO
58 break;
59 case MNT_ERR_NOSOURCE:
e2aedec8
KZ
60 PyErr_SetString(LibmountError, "Required mount source undefined");
61 break;
62 case MNT_ERR_LOOPDEV:
813683a3
OO
63 PyErr_SetString(LibmountError, "Loopdev setup failed");
64 break;
e2aedec8
KZ
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;
813683a3
OO
71 case MNT_ERR_AMBIFS:
72 PyErr_SetString(LibmountError, "Libblkid detected more filesystems on the device");
73 break;
e2aedec8
KZ
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;
813683a3
OO
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{
5d324c6b 104 PyObject *result;
813683a3
OO
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;
5d324c6b 112 result = Py_BuildValue("s", s);
813683a3
OO
113 if (!result)
114 PyErr_SetString(PyExc_RuntimeError, CONSTRUCT_ERR);
115 return result;
116}
117
46407453 118/* wrapper around a common use case for PyUnicode_AsASCIIString() */
813683a3
OO
119char *pystos(PyObject *pys)
120{
46407453
OO
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
813683a3
OO
128 if (!PyString_Check(pys)) {
129 PyErr_SetString(PyExc_TypeError, ARG_ERR);
130 return NULL;
131 }
132 return PyString_AsString(pys);
46407453 133#endif
813683a3
OO
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" \
9e930041 144 "iteration for now. Context.get_{user_,}mflags() differs from the C API\n" \
813683a3
OO
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
46407453
OO
149
150struct module_state {
151 PyObject *error;
813683a3
OO
152};
153
46407453
OO
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;
813683a3 159#endif
46407453
OO
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
9798f7ff
TW
197PyMODINIT_FUNC PyInit_pylibmount(void);
198PyMODINIT_FUNC PyInit_pylibmount(void)
46407453
OO
199#else
200#define INITERROR return
201# ifndef PyMODINIT_FUNC
202# define PyMODINIT_FUNC void
203# endif
813683a3
OO
204PyMODINIT_FUNC initpylibmount(void);
205PyMODINIT_FUNC initpylibmount(void)
46407453 206#endif
813683a3 207{
46407453
OO
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
813683a3
OO
213
214 if (!m)
46407453 215 INITERROR;
b7e47ac1
KZ
216 /*
217 * init debug stuff
218 */
219 if (!(pylibmount_debug_mask & PYMNT_DEBUG_INIT)) {
220 char *str = getenv("PYLIBMOUNT_DEBUG");
221
5aa72646 222 errno = 0;
b7e47ac1
KZ
223 pylibmount_debug_mask = 0;
224 if (str)
87918040 225 pylibmount_debug_mask = strtoul(str, NULL, 0);
5aa72646
KZ
226 if (errno)
227 pylibmount_debug_mask = 0;
813683a3 228
b7e47ac1
KZ
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);
20b222ec 236
b7e47ac1
KZ
237 /*
238 * Add module objects
239 */
813683a3
OO
240 LibmountError = PyErr_NewException("libmount.Error", NULL, NULL);
241 Py_INCREF(LibmountError);
242 PyModule_AddObject(m, "Error", (PyObject *)LibmountError);
243
20b222ec
KZ
244 FS_AddModuleObject(m);
245 Table_AddModuleObject(m);
a5b3be92 246#ifdef __linux__
20b222ec 247 Context_AddModuleObject(m);
a5b3be92 248#endif
813683a3
OO
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);
e6a49887
LB
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);
141bb954 271 PyModule_AddIntConstant(m, "MNT_MS_ROOT_HASH_FILE", MNT_MS_ROOT_HASH_FILE);
9835a4b6
LB
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);
123b1a67 275 PyModule_AddIntConstant(m, "MNT_MS_ROOT_HASH_SIG", MNT_MS_ROOT_HASH_SIG);
813683a3
OO
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);
46407453
OO
320
321#if PY_MAJOR_VERSION >= 3
322 return m;
323#endif
813683a3
OO
324}
325