xref: /netbsd-src/external/bsd/unbound/dist/pythonmod/pythonmod.c (revision 91f7d55fb697b5e0475da4718fa34c3a3ebeac85)
13b6c3722Schristos /*
23b6c3722Schristos  * pythonmod.c: unbound module C wrapper
33b6c3722Schristos  *
43b6c3722Schristos  * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
53b6c3722Schristos  *                     Marek Vavrusa  (xvavru00 AT stud.fit.vutbr.cz)
63b6c3722Schristos  *
73b6c3722Schristos  * This software is open source.
83b6c3722Schristos  *
93b6c3722Schristos  * Redistribution and use in source and binary forms, with or without
103b6c3722Schristos  * modification, are permitted provided that the following conditions
113b6c3722Schristos  * are met:
123b6c3722Schristos  *
133b6c3722Schristos  *    * Redistributions of source code must retain the above copyright notice,
143b6c3722Schristos  *      this list of conditions and the following disclaimer.
153b6c3722Schristos  *
163b6c3722Schristos  *    * Redistributions in binary form must reproduce the above copyright notice,
173b6c3722Schristos  *      this list of conditions and the following disclaimer in the documentation
183b6c3722Schristos  *      and/or other materials provided with the distribution.
193b6c3722Schristos  *
203b6c3722Schristos  *    * Neither the name of the organization nor the names of its
213b6c3722Schristos  *      contributors may be used to endorse or promote products derived from this
223b6c3722Schristos  *      software without specific prior written permission.
233b6c3722Schristos  *
243b6c3722Schristos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
253b6c3722Schristos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
263b6c3722Schristos  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
273b6c3722Schristos  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
283b6c3722Schristos  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
293b6c3722Schristos  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
303b6c3722Schristos  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
313b6c3722Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
323b6c3722Schristos  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
333b6c3722Schristos  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
343b6c3722Schristos  * POSSIBILITY OF SUCH DAMAGE.
353b6c3722Schristos  */
363b6c3722Schristos /**
373b6c3722Schristos  * \file
383b6c3722Schristos  * Python module for unbound.  Calls python script.
393b6c3722Schristos  */
403b6c3722Schristos 
413b6c3722Schristos /* ignore the varargs unused warning from SWIGs internal vararg support */
423b6c3722Schristos #ifdef __GNUC__
433b6c3722Schristos #pragma GCC diagnostic ignored "-Wunused-parameter"
440cd9f4ecSchristos #ifndef __clang__
453b6c3722Schristos #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
463b6c3722Schristos #endif
470cd9f4ecSchristos #endif
483b6c3722Schristos 
493b6c3722Schristos #include "config.h"
503b6c3722Schristos #include "sldns/sbuffer.h"
513b6c3722Schristos 
523b6c3722Schristos #undef _POSIX_C_SOURCE
533b6c3722Schristos #undef _XOPEN_SOURCE
543b6c3722Schristos #include <Python.h>
553b6c3722Schristos 
563b6c3722Schristos #include "pythonmod/pythonmod.h"
573b6c3722Schristos #include "util/module.h"
583b6c3722Schristos #include "util/config_file.h"
593b6c3722Schristos #include "pythonmod_utils.h"
603b6c3722Schristos 
613b6c3722Schristos #ifdef S_SPLINT_S
623b6c3722Schristos typedef struct PyObject PyObject;
633b6c3722Schristos typedef struct PyThreadState PyThreadState;
643b6c3722Schristos typedef void* PyGILState_STATE;
653b6c3722Schristos #endif
663b6c3722Schristos 
673b6c3722Schristos /**
6801049ae6Schristos  *  counter for python module instances
6901049ae6Schristos  *  incremented by pythonmod_init(...)
7001049ae6Schristos  */
7101049ae6Schristos int py_mod_count = 0;
7201049ae6Schristos 
7301049ae6Schristos /** Python main thread */
7401049ae6Schristos PyThreadState* mainthr;
7501049ae6Schristos 
7601049ae6Schristos /**
773b6c3722Schristos  * Global state for the module.
783b6c3722Schristos  */
793b6c3722Schristos struct pythonmod_env {
803b6c3722Schristos 
813b6c3722Schristos 	/** Python script filename. */
823b6c3722Schristos 	const char* fname;
833b6c3722Schristos 
843b6c3722Schristos 	/** Python module. */
853b6c3722Schristos 	PyObject* module;
863b6c3722Schristos 
873b6c3722Schristos 	/** Module init function */
883b6c3722Schristos 	PyObject* func_init;
893b6c3722Schristos 	/** Module deinit function */
903b6c3722Schristos 	PyObject* func_deinit;
913b6c3722Schristos 	/** Module operate function */
923b6c3722Schristos 	PyObject* func_operate;
933b6c3722Schristos 	/** Module super_inform function */
943b6c3722Schristos 	PyObject* func_inform;
953b6c3722Schristos 
963b6c3722Schristos 	/** Python dictionary. */
973b6c3722Schristos 	PyObject* dict;
983b6c3722Schristos 
993b6c3722Schristos 	/** Module data. */
1003b6c3722Schristos 	PyObject* data;
1013b6c3722Schristos 
1023b6c3722Schristos 	/** Module qstate. */
1033b6c3722Schristos 	struct module_qstate* qstate;
1043b6c3722Schristos };
1053b6c3722Schristos 
1063b6c3722Schristos /**
1073b6c3722Schristos  * Per query state for the iterator module.
1083b6c3722Schristos  */
1093b6c3722Schristos struct pythonmod_qstate {
1103b6c3722Schristos 
1113b6c3722Schristos 	/** Module per query data. */
1123b6c3722Schristos 	PyObject* data;
1133b6c3722Schristos };
1143b6c3722Schristos 
115*91f7d55fSchristos /* The dict from __main__ could have remnants from a previous script
116*91f7d55fSchristos  * invocation, in a multi python module setup. Usually this is fine since newer
117*91f7d55fSchristos  * scripts will update their values. The obvious erroneous case is when mixing
118*91f7d55fSchristos  * python scripts that make use of both 'init' and 'init_standard'. This
119*91f7d55fSchristos  * results in 'init_standard' to persist on following scripts that don't use it
120*91f7d55fSchristos  * (thus not replacing it). This is also problematic in case where a script
121*91f7d55fSchristos  * does not define a required function but a previously loaded script did. The
122*91f7d55fSchristos  * current solution is to make sure to clean offensive remnants that influence
123*91f7d55fSchristos  * further parsing of the individual scripts.
124*91f7d55fSchristos  */
125*91f7d55fSchristos static void
clean_python_function_objects(PyObject * dict)126*91f7d55fSchristos clean_python_function_objects(PyObject* dict) {
127*91f7d55fSchristos 	const char* function_names[] = {
128*91f7d55fSchristos 		"init",
129*91f7d55fSchristos 		"init_standard",
130*91f7d55fSchristos 		"deinit",
131*91f7d55fSchristos 		"operate",
132*91f7d55fSchristos 		"inform_super"
133*91f7d55fSchristos 	};
134*91f7d55fSchristos 	size_t i;
135*91f7d55fSchristos 
136*91f7d55fSchristos 	for(i=0; i<sizeof(function_names)/sizeof(function_names[0]); i++) {
137*91f7d55fSchristos 		if(PyDict_GetItemString(dict, function_names[i]) != NULL) {
138*91f7d55fSchristos 			PyDict_DelItemString(dict, function_names[i]);
139*91f7d55fSchristos 		}
140*91f7d55fSchristos 	}
141*91f7d55fSchristos };
142*91f7d55fSchristos 
1433b6c3722Schristos /* Generated */
1443b6c3722Schristos #ifndef S_SPLINT_S
1453b6c3722Schristos #include "pythonmod/interface.h"
1463b6c3722Schristos #endif
1473b6c3722Schristos 
148f42d8de7Schristos /** log python error */
149f42d8de7Schristos static void
log_py_err(void)150f42d8de7Schristos log_py_err(void)
151f42d8de7Schristos {
152f42d8de7Schristos 	char *result = NULL;
153f42d8de7Schristos 	const char* iomod = "cStringIO";
154f42d8de7Schristos 	PyObject *modStringIO = NULL;
155f42d8de7Schristos 	PyObject *modTB = NULL;
156f42d8de7Schristos 	PyObject *obFuncStringIO = NULL;
157f42d8de7Schristos 	PyObject *obStringIO = NULL;
158f42d8de7Schristos 	PyObject *obFuncTB = NULL;
159f42d8de7Schristos 	PyObject *argsTB = NULL;
160f42d8de7Schristos 	PyObject *obResult = NULL;
161f42d8de7Schristos 	PyObject *ascstr = NULL;
162f42d8de7Schristos 	PyObject *exc_typ, *exc_val, *exc_tb;
163f42d8de7Schristos 
164f42d8de7Schristos 	/* Fetch the error state now before we cruch it */
165f42d8de7Schristos 	/* exc val contains the error message
166f42d8de7Schristos 	 * exc tb contains stack traceback and other info. */
167f42d8de7Schristos 	PyErr_Fetch(&exc_typ, &exc_val, &exc_tb);
168f42d8de7Schristos 	PyErr_NormalizeException(&exc_typ, &exc_val, &exc_tb);
169f42d8de7Schristos 
170f42d8de7Schristos 	/* Import the modules we need - cStringIO and traceback */
171f42d8de7Schristos 	modStringIO = PyImport_ImportModule("cStringIO");
172f42d8de7Schristos 	if (modStringIO==NULL) {
173f42d8de7Schristos 		/* python 1.4 and before */
174f42d8de7Schristos 		modStringIO = PyImport_ImportModule("StringIO");
175f42d8de7Schristos 		iomod = "StringIO";
176f42d8de7Schristos 	}
177f42d8de7Schristos 	if (modStringIO==NULL) {
178f42d8de7Schristos 		/* python 3 */
179f42d8de7Schristos 		modStringIO = PyImport_ImportModule("io");
180f42d8de7Schristos 		iomod = "io";
181f42d8de7Schristos 	}
182f42d8de7Schristos 	if (modStringIO==NULL) {
183f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
184f42d8de7Schristos 			"cannot ImportModule cStringIO or StringIO or io");
185f42d8de7Schristos 		goto cleanup;
186f42d8de7Schristos 	}
187f42d8de7Schristos 	modTB = PyImport_ImportModule("traceback");
188f42d8de7Schristos 	if (modTB==NULL) {
189f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
190f42d8de7Schristos 			"cannot ImportModule traceback");
191f42d8de7Schristos 		goto cleanup;
192f42d8de7Schristos 	}
193f42d8de7Schristos 
194f42d8de7Schristos 	/* Construct a cStringIO object */
195f42d8de7Schristos 	obFuncStringIO = PyObject_GetAttrString(modStringIO, "StringIO");
196f42d8de7Schristos 	if (obFuncStringIO==NULL) {
197f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
198f42d8de7Schristos 			"cannot GetAttrString %s.StringIO", iomod);
199f42d8de7Schristos 		goto cleanup;
200f42d8de7Schristos 	}
201f42d8de7Schristos 	obStringIO = PyObject_CallObject(obFuncStringIO, NULL);
202f42d8de7Schristos 	if (obStringIO==NULL) {
203f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
204f42d8de7Schristos 			"cannot call %s.StringIO()", iomod);
205f42d8de7Schristos 		goto cleanup;
206f42d8de7Schristos 	}
207f42d8de7Schristos 
208f42d8de7Schristos 	/* Get the traceback.print_exception function, and call it. */
209f42d8de7Schristos 	obFuncTB = PyObject_GetAttrString(modTB, "print_exception");
210f42d8de7Schristos 	if (obFuncTB==NULL) {
211f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
212f42d8de7Schristos 			"cannot GetAttrString traceback.print_exception");
213f42d8de7Schristos 		goto cleanup;
214f42d8de7Schristos 	}
215f42d8de7Schristos 	argsTB = Py_BuildValue("OOOOO", (exc_typ ? exc_typ : Py_None),
216f42d8de7Schristos 		(exc_val ? exc_val : Py_None), (exc_tb  ? exc_tb  : Py_None),
217f42d8de7Schristos 		Py_None, obStringIO);
218f42d8de7Schristos 	if (argsTB==NULL) {
219f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
220f42d8de7Schristos 			"cannot BuildValue for print_exception");
221f42d8de7Schristos 		goto cleanup;
222f42d8de7Schristos 	}
223f42d8de7Schristos 
224f42d8de7Schristos 	obResult = PyObject_CallObject(obFuncTB, argsTB);
225f42d8de7Schristos 	if (obResult==NULL) {
226f42d8de7Schristos 		PyErr_Print();
227f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
228f42d8de7Schristos 			"call traceback.print_exception() failed");
229f42d8de7Schristos 		goto cleanup;
230f42d8de7Schristos 	}
231f42d8de7Schristos 
232f42d8de7Schristos 	/* Now call the getvalue() method in the StringIO instance */
233f42d8de7Schristos 	Py_DECREF(obFuncStringIO);
234f42d8de7Schristos 	obFuncStringIO = PyObject_GetAttrString(obStringIO, "getvalue");
235f42d8de7Schristos 	if (obFuncStringIO==NULL) {
236f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
237f42d8de7Schristos 			"cannot GetAttrString StringIO.getvalue");
238f42d8de7Schristos 		goto cleanup;
239f42d8de7Schristos 	}
240f42d8de7Schristos 	Py_DECREF(obResult);
241f42d8de7Schristos 	obResult = PyObject_CallObject(obFuncStringIO, NULL);
242f42d8de7Schristos 	if (obResult==NULL) {
243f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
244f42d8de7Schristos 			"call StringIO.getvalue() failed");
245f42d8de7Schristos 		goto cleanup;
246f42d8de7Schristos 	}
247f42d8de7Schristos 
248f42d8de7Schristos 	/* And it should be a string all ready to go - duplicate it. */
249f42d8de7Schristos 	if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
250f42d8de7Schristos 		log_err("pythonmod: cannot print exception, "
251f42d8de7Schristos 			"StringIO.getvalue() result did not String_Check"
252f42d8de7Schristos 			" or Unicode_Check");
253f42d8de7Schristos 		goto cleanup;
254f42d8de7Schristos 	}
255f42d8de7Schristos 	if(PyString_Check(obResult)) {
256f42d8de7Schristos 		result = PyString_AsString(obResult);
257f42d8de7Schristos 	} else {
258f42d8de7Schristos 		ascstr = PyUnicode_AsASCIIString(obResult);
259f42d8de7Schristos 		result = PyBytes_AsString(ascstr);
260f42d8de7Schristos 	}
261f42d8de7Schristos 	log_err("pythonmod: python error: %s", result);
262f42d8de7Schristos 
263f42d8de7Schristos cleanup:
264f42d8de7Schristos 	Py_XDECREF(modStringIO);
265f42d8de7Schristos 	Py_XDECREF(modTB);
266f42d8de7Schristos 	Py_XDECREF(obFuncStringIO);
267f42d8de7Schristos 	Py_XDECREF(obStringIO);
268f42d8de7Schristos 	Py_XDECREF(obFuncTB);
269f42d8de7Schristos 	Py_XDECREF(argsTB);
270f42d8de7Schristos 	Py_XDECREF(obResult);
271f42d8de7Schristos 	Py_XDECREF(ascstr);
272f42d8de7Schristos 
273f42d8de7Schristos 	/* clear the exception, by not restoring it */
274f42d8de7Schristos 	/* Restore the exception state */
275f42d8de7Schristos 	/* PyErr_Restore(exc_typ, exc_val, exc_tb); */
2767a540f2bSchristos 	/* when using PyErr_Restore there is no need to Py_XDECREF for
2777a540f2bSchristos 	 * these 3 pointers. */
2787a540f2bSchristos 	Py_XDECREF(exc_typ);
2797a540f2bSchristos 	Py_XDECREF(exc_val);
2807a540f2bSchristos 	Py_XDECREF(exc_tb);
281f42d8de7Schristos }
282f42d8de7Schristos 
283*91f7d55fSchristos /* we only want to unwind Python once at exit */
284*91f7d55fSchristos static void
pythonmod_atexit(void)285*91f7d55fSchristos pythonmod_atexit(void)
286*91f7d55fSchristos {
287*91f7d55fSchristos    log_assert(py_mod_count == 0);
288*91f7d55fSchristos    log_assert(mainthr != NULL);
289*91f7d55fSchristos 
290*91f7d55fSchristos    PyEval_RestoreThread(mainthr);
291*91f7d55fSchristos    Py_Finalize();
292*91f7d55fSchristos }
293*91f7d55fSchristos 
pythonmod_init(struct module_env * env,int id)2943b6c3722Schristos int pythonmod_init(struct module_env* env, int id)
2953b6c3722Schristos {
29601049ae6Schristos    int py_mod_idx = py_mod_count++;
29701049ae6Schristos 
2983b6c3722Schristos    /* Initialize module */
2993b6c3722Schristos    FILE* script_py = NULL;
300*91f7d55fSchristos    PyObject* py_init_arg = NULL, *res = NULL, *fname = NULL;
3013b6c3722Schristos    PyGILState_STATE gil;
30201049ae6Schristos    int init_standard = 1, i = 0;
303f42d8de7Schristos #if PY_MAJOR_VERSION < 3
304f42d8de7Schristos    PyObject* PyFileObject = NULL;
305f42d8de7Schristos #endif
30601049ae6Schristos    struct config_strlist* cfg_item = env->cfg->python_script;
3070cd9f4ecSchristos 
3083b6c3722Schristos    struct pythonmod_env* pe = (struct pythonmod_env*)calloc(1, sizeof(struct pythonmod_env));
3093b6c3722Schristos    if (!pe)
3103b6c3722Schristos    {
3113b6c3722Schristos       log_err("pythonmod: malloc failure");
3123b6c3722Schristos       return 0;
3133b6c3722Schristos    }
3143b6c3722Schristos 
3153b6c3722Schristos    env->modinfo[id] = (void*) pe;
3163b6c3722Schristos 
3173b6c3722Schristos    /* Initialize module */
31801049ae6Schristos    pe->fname=NULL; i = 0;
31901049ae6Schristos    while (cfg_item!=NULL) {
32001049ae6Schristos       if (py_mod_idx==i++) {
32101049ae6Schristos          pe->fname=cfg_item->str;
32201049ae6Schristos          break;
32301049ae6Schristos       }
32401049ae6Schristos       cfg_item = cfg_item->next;
32501049ae6Schristos    }
3263b6c3722Schristos    if(pe->fname==NULL || pe->fname[0]==0) {
32701049ae6Schristos       log_err("pythonmod[%d]: no script given.", py_mod_idx);
3283b6c3722Schristos       return 0;
3293b6c3722Schristos    }
3303b6c3722Schristos 
3313b6c3722Schristos    /* Initialize Python libraries */
33201049ae6Schristos    if (py_mod_count==1 && !Py_IsInitialized())
3333b6c3722Schristos    {
334*91f7d55fSchristos #if PY_VERSION_HEX >= 0x03080000
335*91f7d55fSchristos       PyStatus status;
336*91f7d55fSchristos       PyPreConfig preconfig;
337*91f7d55fSchristos       PyConfig config;
338*91f7d55fSchristos #endif
3393b6c3722Schristos #if PY_MAJOR_VERSION >= 3
3403b6c3722Schristos       wchar_t progname[8];
3413b6c3722Schristos       mbstowcs(progname, "unbound", 8);
3423b6c3722Schristos #else
3433b6c3722Schristos       char *progname = "unbound";
3443b6c3722Schristos #endif
345*91f7d55fSchristos #if PY_VERSION_HEX < 0x03080000
3463b6c3722Schristos       Py_SetProgramName(progname);
347*91f7d55fSchristos #else
348*91f7d55fSchristos       /* Python must be preinitialized, before the PyImport_AppendInittab
349*91f7d55fSchristos        * call. */
350*91f7d55fSchristos       PyPreConfig_InitPythonConfig(&preconfig);
351*91f7d55fSchristos       status = Py_PreInitialize(&preconfig);
352*91f7d55fSchristos       if(PyStatus_Exception(status)) {
353*91f7d55fSchristos 	log_err("python exception in Py_PreInitialize: %s%s%s",
354*91f7d55fSchristos 		(status.func?status.func:""), (status.func?": ":""),
355*91f7d55fSchristos 		(status.err_msg?status.err_msg:""));
356*91f7d55fSchristos 	return 0;
357*91f7d55fSchristos       }
358*91f7d55fSchristos #endif
3593b6c3722Schristos       Py_NoSiteFlag = 1;
3603b6c3722Schristos #if PY_MAJOR_VERSION >= 3
3613b6c3722Schristos       PyImport_AppendInittab(SWIG_name, (void*)SWIG_init);
3623b6c3722Schristos #endif
363*91f7d55fSchristos #if PY_VERSION_HEX < 0x03080000
3643b6c3722Schristos       Py_Initialize();
365*91f7d55fSchristos #else
366*91f7d55fSchristos       PyConfig_InitPythonConfig(&config);
367*91f7d55fSchristos       status = PyConfig_SetString(&config, &config.program_name, progname);
368*91f7d55fSchristos       if(PyStatus_Exception(status)) {
369*91f7d55fSchristos 	log_err("python exception in PyConfig_SetString(.. program_name ..): %s%s%s",
370*91f7d55fSchristos 		(status.func?status.func:""), (status.func?": ":""),
371*91f7d55fSchristos 		(status.err_msg?status.err_msg:""));
372*91f7d55fSchristos 	PyConfig_Clear(&config);
373*91f7d55fSchristos 	return 0;
374*91f7d55fSchristos       }
375*91f7d55fSchristos       config.site_import = 0;
376*91f7d55fSchristos       status = Py_InitializeFromConfig(&config);
377*91f7d55fSchristos       if(PyStatus_Exception(status)) {
378*91f7d55fSchristos 	log_err("python exception in Py_InitializeFromConfig: %s%s%s",
379*91f7d55fSchristos 		(status.func?status.func:""), (status.func?": ":""),
380*91f7d55fSchristos 		(status.err_msg?status.err_msg:""));
381*91f7d55fSchristos 	PyConfig_Clear(&config);
382*91f7d55fSchristos 	return 0;
383*91f7d55fSchristos       }
384*91f7d55fSchristos       PyConfig_Clear(&config);
385*91f7d55fSchristos #endif
3867a540f2bSchristos #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION <= 6)
3877a540f2bSchristos       /* initthreads only for python 3.6 and older */
3883b6c3722Schristos       PyEval_InitThreads();
3897a540f2bSchristos #endif
3903b6c3722Schristos       SWIG_init();
39101049ae6Schristos       mainthr = PyEval_SaveThread();
392*91f7d55fSchristos 
393*91f7d55fSchristos       /* register callback to unwind Python at exit */
394*91f7d55fSchristos       atexit(pythonmod_atexit);
3953b6c3722Schristos    }
3963b6c3722Schristos 
3973b6c3722Schristos    gil = PyGILState_Ensure();
3983b6c3722Schristos 
39901049ae6Schristos    if (py_mod_count==1) {
4003b6c3722Schristos       /* Initialize Python */
401*91f7d55fSchristos       if(PyRun_SimpleString("import sys \n") < 0 ) {
402*91f7d55fSchristos          log_err("pythonmod: cannot initialize core module: unboundmodule.py");
403*91f7d55fSchristos          goto python_init_fail;
404*91f7d55fSchristos       }
4053b6c3722Schristos       PyRun_SimpleString("sys.path.append('.') \n");
406*91f7d55fSchristos       PyRun_SimpleString("sys.path.append('"RUN_DIR"') \n");
407*91f7d55fSchristos       PyRun_SimpleString("sys.path.append('"SHARE_DIR"') \n");
4083b6c3722Schristos       if(env->cfg->directory && env->cfg->directory[0]) {
4093b6c3722Schristos          char wdir[1524];
4103b6c3722Schristos          snprintf(wdir, sizeof(wdir), "sys.path.append('%s') \n",
4113b6c3722Schristos          env->cfg->directory);
4123b6c3722Schristos          PyRun_SimpleString(wdir);
4133b6c3722Schristos       }
414*91f7d55fSchristos       if(PyRun_SimpleString("import site\n") < 0) {
415*91f7d55fSchristos          log_err("pythonmod: cannot initialize core module: unboundmodule.py");
416*91f7d55fSchristos          goto python_init_fail;
417*91f7d55fSchristos       }
418*91f7d55fSchristos       if(PyRun_SimpleString("sys.path.extend(site.getsitepackages())\n") < 0) {
419*91f7d55fSchristos          log_err("pythonmod: cannot initialize core module: unboundmodule.py");
420*91f7d55fSchristos          goto python_init_fail;
421*91f7d55fSchristos       }
4223b6c3722Schristos       if(PyRun_SimpleString("from unboundmodule import *\n") < 0)
4233b6c3722Schristos       {
4243b6c3722Schristos          log_err("pythonmod: cannot initialize core module: unboundmodule.py");
425*91f7d55fSchristos          goto python_init_fail;
4263b6c3722Schristos       }
42701049ae6Schristos    }
4283b6c3722Schristos 
4293b6c3722Schristos    /* Check Python file load */
430f42d8de7Schristos    /* uses python to open the file, this works on other platforms,
431f42d8de7Schristos     * eg. Windows, to open the file in the correct mode for python */
432f42d8de7Schristos #if PY_MAJOR_VERSION < 3
433f42d8de7Schristos    PyFileObject = PyFile_FromString((char*)pe->fname, "r");
434f42d8de7Schristos    script_py = PyFile_AsFile(PyFileObject);
435f42d8de7Schristos #else
4367a540f2bSchristos    script_py = fopen(pe->fname, "r");
437f42d8de7Schristos #endif
438f42d8de7Schristos    if (script_py == NULL)
4393b6c3722Schristos    {
4403b6c3722Schristos       log_err("pythonmod: can't open file %s for reading", pe->fname);
441*91f7d55fSchristos       goto python_init_fail;
4423b6c3722Schristos    }
4433b6c3722Schristos 
4443b6c3722Schristos    /* Load file */
4453b6c3722Schristos    pe->module = PyImport_AddModule("__main__");
446*91f7d55fSchristos    Py_XINCREF(pe->module);
4473b6c3722Schristos    pe->dict = PyModule_GetDict(pe->module);
448*91f7d55fSchristos    Py_XINCREF(pe->dict);
449*91f7d55fSchristos    clean_python_function_objects(pe->dict);
4503b6c3722Schristos 
451*91f7d55fSchristos    pe->data = PyDict_New();
452*91f7d55fSchristos    /* add the script filename to the global "mod_env" for trivial access */
453*91f7d55fSchristos    fname = PyString_FromString(pe->fname);
454*91f7d55fSchristos    if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
455*91f7d55fSchristos 	log_err("pythonmod: could not add item to dictionary");
456*91f7d55fSchristos 	Py_XDECREF(fname);
457*91f7d55fSchristos 	goto python_init_fail;
458*91f7d55fSchristos    }
459*91f7d55fSchristos    Py_XDECREF(fname);
460*91f7d55fSchristos    Py_XINCREF(pe->data);  /* reference will be stolen below */
461*91f7d55fSchristos    if(PyModule_AddObject(pe->module, "mod_env", pe->data) < 0) {
462*91f7d55fSchristos 	log_err("pythonmod: could not add mod_env object");
463*91f7d55fSchristos 	Py_XDECREF(pe->data);  /* 2 times, here and on python_init_fail; */
464*91f7d55fSchristos 	                       /* on failure the reference is not stolen */
465*91f7d55fSchristos 	goto python_init_fail;
466*91f7d55fSchristos    }
4673b6c3722Schristos 
468f42d8de7Schristos    if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
4697a540f2bSchristos #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
4707a540f2bSchristos       /* for python before 3.9 */
4713b6c3722Schristos       log_err("pythonmod: can't parse Python script %s", pe->fname);
472f42d8de7Schristos       /* print the error to logs too, run it again */
473f42d8de7Schristos       fseek(script_py, 0, SEEK_SET);
474f42d8de7Schristos       /* we don't run the file, like this, because then side-effects
475f42d8de7Schristos        *    s = PyRun_File(script_py, pe->fname, Py_file_input,
476f42d8de7Schristos        *        PyModule_GetDict(PyImport_AddModule("__main__")), pe->dict);
477f42d8de7Schristos        * could happen (again). Instead we parse the file again to get
478f42d8de7Schristos        * the error string in the logs, for when the daemon has stderr
479f42d8de7Schristos        * removed.  SimpleFile run already printed to stderr, for then
480f42d8de7Schristos        * this is called from unbound-checkconf or unbound -dd the user
481f42d8de7Schristos        * has a nice formatted error.
482f42d8de7Schristos       */
483f42d8de7Schristos       /* ignore the NULL return of _node, it is NULL due to the parse failure
484f42d8de7Schristos        * that we are expecting */
485f42d8de7Schristos       (void)PyParser_SimpleParseFile(script_py, pe->fname, Py_file_input);
4867a540f2bSchristos #else
4877a540f2bSchristos       /* for python 3.9 and newer */
4887a540f2bSchristos       char* fstr = NULL;
4897a540f2bSchristos       size_t flen = 0;
4907a540f2bSchristos       log_err("pythonmod: can't parse Python script %s", pe->fname);
4917a540f2bSchristos       /* print the error to logs too, run it again */
4927a540f2bSchristos       fseek(script_py, 0, SEEK_END);
4937a540f2bSchristos       flen = (size_t)ftell(script_py);
4947a540f2bSchristos       fstr = malloc(flen+1);
4957a540f2bSchristos       if(!fstr) {
4967a540f2bSchristos 	      log_err("malloc failure to print parse error");
497*91f7d55fSchristos 
498*91f7d55fSchristos /* close the file */
499*91f7d55fSchristos #if PY_MAJOR_VERSION < 3
500*91f7d55fSchristos 	      Py_XDECREF(PyFileObject);
501*91f7d55fSchristos #else
5027a540f2bSchristos 	      fclose(script_py);
503*91f7d55fSchristos #endif
504*91f7d55fSchristos 
505*91f7d55fSchristos 	      goto python_init_fail;
5067a540f2bSchristos       }
5077a540f2bSchristos       fseek(script_py, 0, SEEK_SET);
5087a540f2bSchristos       if(fread(fstr, flen, 1, script_py) < 1) {
5097a540f2bSchristos 	      log_err("file read failed to print parse error: %s: %s",
5107a540f2bSchristos 		pe->fname, strerror(errno));
5117a540f2bSchristos 	      free(fstr);
512*91f7d55fSchristos 
513*91f7d55fSchristos /* close the file */
514*91f7d55fSchristos #if PY_MAJOR_VERSION < 3
515*91f7d55fSchristos 	      Py_XDECREF(PyFileObject);
516*91f7d55fSchristos #else
517*91f7d55fSchristos 	      fclose(script_py);
518*91f7d55fSchristos #endif
519*91f7d55fSchristos 
520*91f7d55fSchristos 	      goto python_init_fail;
5217a540f2bSchristos       }
5227a540f2bSchristos       fstr[flen] = 0;
5237a540f2bSchristos       /* we compile the string, but do not run it, to stop side-effects */
5247a540f2bSchristos       /* ignore the NULL return of _node, it is NULL due to the parse failure
5257a540f2bSchristos        * that we are expecting */
5267a540f2bSchristos       (void)Py_CompileString(fstr, pe->fname, Py_file_input);
5277a540f2bSchristos #endif
528*91f7d55fSchristos 
529f42d8de7Schristos       log_py_err();
530*91f7d55fSchristos 
531*91f7d55fSchristos /* close the file */
532*91f7d55fSchristos #if PY_MAJOR_VERSION < 3
533*91f7d55fSchristos       Py_XDECREF(PyFileObject);
534*91f7d55fSchristos #else
53501049ae6Schristos       fclose(script_py);
536*91f7d55fSchristos #endif
537*91f7d55fSchristos 
5387a540f2bSchristos #if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
5397a540f2bSchristos       /* no cleanup needed for python before 3.9 */
5407a540f2bSchristos #else
5417a540f2bSchristos       /* cleanup for python 3.9 and newer */
5427a540f2bSchristos       free(fstr);
5437a540f2bSchristos #endif
544*91f7d55fSchristos       goto python_init_fail;
5453b6c3722Schristos    }
546*91f7d55fSchristos 
547*91f7d55fSchristos /* close the file */
548f42d8de7Schristos #if PY_MAJOR_VERSION < 3
549f42d8de7Schristos    Py_XDECREF(PyFileObject);
550f42d8de7Schristos #else
5513b6c3722Schristos    fclose(script_py);
552f42d8de7Schristos #endif
5533b6c3722Schristos 
5540cd9f4ecSchristos    if ((pe->func_init = PyDict_GetItemString(pe->dict, "init_standard")) == NULL)
5550cd9f4ecSchristos    {
5560cd9f4ecSchristos       init_standard = 0;
5573b6c3722Schristos       if ((pe->func_init = PyDict_GetItemString(pe->dict, "init")) == NULL)
5583b6c3722Schristos       {
5593b6c3722Schristos          log_err("pythonmod: function init is missing in %s", pe->fname);
560*91f7d55fSchristos          goto python_init_fail;
5613b6c3722Schristos       }
5620cd9f4ecSchristos    }
563*91f7d55fSchristos    Py_XINCREF(pe->func_init);
5643b6c3722Schristos    if ((pe->func_deinit = PyDict_GetItemString(pe->dict, "deinit")) == NULL)
5653b6c3722Schristos    {
5663b6c3722Schristos       log_err("pythonmod: function deinit is missing in %s", pe->fname);
567*91f7d55fSchristos       goto python_init_fail;
5683b6c3722Schristos    }
569*91f7d55fSchristos    Py_XINCREF(pe->func_deinit);
5703b6c3722Schristos    if ((pe->func_operate = PyDict_GetItemString(pe->dict, "operate")) == NULL)
5713b6c3722Schristos    {
5723b6c3722Schristos       log_err("pythonmod: function operate is missing in %s", pe->fname);
573*91f7d55fSchristos       goto python_init_fail;
5743b6c3722Schristos    }
575*91f7d55fSchristos    Py_XINCREF(pe->func_operate);
5763b6c3722Schristos    if ((pe->func_inform = PyDict_GetItemString(pe->dict, "inform_super")) == NULL)
5773b6c3722Schristos    {
5783b6c3722Schristos       log_err("pythonmod: function inform_super is missing in %s", pe->fname);
579*91f7d55fSchristos       goto python_init_fail;
5803b6c3722Schristos    }
581*91f7d55fSchristos    Py_XINCREF(pe->func_inform);
5823b6c3722Schristos 
5830cd9f4ecSchristos    if (init_standard)
5840cd9f4ecSchristos    {
5850cd9f4ecSchristos       py_init_arg = SWIG_NewPointerObj((void*) env, SWIGTYPE_p_module_env, 0);
5860cd9f4ecSchristos    }
5870cd9f4ecSchristos    else
5880cd9f4ecSchristos    {
5890cd9f4ecSchristos       py_init_arg = SWIG_NewPointerObj((void*) env->cfg,
5900cd9f4ecSchristos         SWIGTYPE_p_config_file, 0);
5910cd9f4ecSchristos    }
5920cd9f4ecSchristos    res = PyObject_CallFunction(pe->func_init, "iO", id, py_init_arg);
5933b6c3722Schristos    if (PyErr_Occurred())
5943b6c3722Schristos    {
5953b6c3722Schristos       log_err("pythonmod: Exception occurred in function init");
596f42d8de7Schristos       log_py_err();
597*91f7d55fSchristos       goto python_init_fail;
598*91f7d55fSchristos    }
599*91f7d55fSchristos 
600*91f7d55fSchristos    Py_XDECREF(res);
601*91f7d55fSchristos    Py_XDECREF(py_init_arg);
602*91f7d55fSchristos    PyGILState_Release(gil);
603*91f7d55fSchristos    return 1;
604*91f7d55fSchristos 
605*91f7d55fSchristos python_init_fail:
606*91f7d55fSchristos    Py_XDECREF(pe->module);
607*91f7d55fSchristos    Py_XDECREF(pe->dict);
608*91f7d55fSchristos    Py_XDECREF(pe->data);
609*91f7d55fSchristos    Py_XDECREF(pe->func_init);
610*91f7d55fSchristos    Py_XDECREF(pe->func_deinit);
611*91f7d55fSchristos    Py_XDECREF(pe->func_operate);
612*91f7d55fSchristos    Py_XDECREF(pe->func_inform);
6130cd9f4ecSchristos    Py_XDECREF(res);
6140cd9f4ecSchristos    Py_XDECREF(py_init_arg);
6150cd9f4ecSchristos    PyGILState_Release(gil);
6160cd9f4ecSchristos    return 0;
6173b6c3722Schristos }
6183b6c3722Schristos 
pythonmod_deinit(struct module_env * env,int id)6193b6c3722Schristos void pythonmod_deinit(struct module_env* env, int id)
6203b6c3722Schristos {
621*91f7d55fSchristos    int cbtype;
6223b6c3722Schristos    struct pythonmod_env* pe = env->modinfo[id];
6233b6c3722Schristos    if(pe == NULL)
6243b6c3722Schristos       return;
6253b6c3722Schristos 
6263b6c3722Schristos    /* Free Python resources */
6273b6c3722Schristos    if(pe->module != NULL)
6283b6c3722Schristos    {
6293b6c3722Schristos       PyObject* res;
6303b6c3722Schristos       PyGILState_STATE gil = PyGILState_Ensure();
6313b6c3722Schristos 
6323b6c3722Schristos       /* Deinit module */
6333b6c3722Schristos       res = PyObject_CallFunction(pe->func_deinit, "i", id);
6343b6c3722Schristos       if (PyErr_Occurred()) {
6353b6c3722Schristos          log_err("pythonmod: Exception occurred in function deinit");
636f42d8de7Schristos          log_py_err();
6373b6c3722Schristos       }
6383b6c3722Schristos       /* Free result if any */
6393b6c3722Schristos       Py_XDECREF(res);
6403b6c3722Schristos       /* Free shared data if any */
641*91f7d55fSchristos       Py_XDECREF(pe->module);
642*91f7d55fSchristos       Py_XDECREF(pe->dict);
6433b6c3722Schristos       Py_XDECREF(pe->data);
644*91f7d55fSchristos       Py_XDECREF(pe->func_init);
645*91f7d55fSchristos       Py_XDECREF(pe->func_deinit);
646*91f7d55fSchristos       Py_XDECREF(pe->func_inform);
647*91f7d55fSchristos       Py_XDECREF(pe->func_operate);
6483b6c3722Schristos       PyGILState_Release(gil);
6493b6c3722Schristos 
650*91f7d55fSchristos       py_mod_count--;
6513b6c3722Schristos    }
6523b6c3722Schristos    pe->fname = NULL;
6533b6c3722Schristos    free(pe);
6543b6c3722Schristos 
655*91f7d55fSchristos    /* iterate over all possible callback types and clean up each in turn */
656*91f7d55fSchristos    for (cbtype = 0; cbtype < inplace_cb_types_total; cbtype++)
657*91f7d55fSchristos       inplace_cb_delete(env, cbtype, id);
658*91f7d55fSchristos 
6593b6c3722Schristos    /* Module is deallocated in Python */
6603b6c3722Schristos    env->modinfo[id] = NULL;
6613b6c3722Schristos }
6623b6c3722Schristos 
pythonmod_inform_super(struct module_qstate * qstate,int id,struct module_qstate * super)6633b6c3722Schristos void pythonmod_inform_super(struct module_qstate* qstate, int id, struct module_qstate* super)
6643b6c3722Schristos {
6653b6c3722Schristos    struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
6663b6c3722Schristos    struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
6673b6c3722Schristos    PyObject* py_qstate, *py_sqstate, *res;
6683b6c3722Schristos    PyGILState_STATE gil = PyGILState_Ensure();
6693b6c3722Schristos 
6703b6c3722Schristos    log_query_info(VERB_ALGO, "pythonmod: inform_super, sub is", &qstate->qinfo);
6713b6c3722Schristos    log_query_info(VERB_ALGO, "super is", &super->qinfo);
6723b6c3722Schristos 
6733b6c3722Schristos    py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
6743b6c3722Schristos    py_sqstate = SWIG_NewPointerObj((void*) super, SWIGTYPE_p_module_qstate, 0);
6753b6c3722Schristos 
6763b6c3722Schristos    res = PyObject_CallFunction(pe->func_inform, "iOOO", id, py_qstate,
6773b6c3722Schristos 	py_sqstate, pq->data);
6783b6c3722Schristos 
6793b6c3722Schristos    if (PyErr_Occurred())
6803b6c3722Schristos    {
6813b6c3722Schristos       log_err("pythonmod: Exception occurred in function inform_super");
682f42d8de7Schristos       log_py_err();
6833b6c3722Schristos       qstate->ext_state[id] = module_error;
6843b6c3722Schristos    }
6853b6c3722Schristos    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
6863b6c3722Schristos    {
6873b6c3722Schristos       log_err("pythonmod: python returned bad code in inform_super");
6883b6c3722Schristos       qstate->ext_state[id] = module_error;
6893b6c3722Schristos    }
6903b6c3722Schristos 
6913b6c3722Schristos    Py_XDECREF(res);
6923b6c3722Schristos    Py_XDECREF(py_sqstate);
6933b6c3722Schristos    Py_XDECREF(py_qstate);
6943b6c3722Schristos 
6953b6c3722Schristos    PyGILState_Release(gil);
6963b6c3722Schristos }
6973b6c3722Schristos 
pythonmod_operate(struct module_qstate * qstate,enum module_ev event,int id,struct outbound_entry * ATTR_UNUSED (outbound))6983b6c3722Schristos void pythonmod_operate(struct module_qstate* qstate, enum module_ev event,
6993b6c3722Schristos 	int id, struct outbound_entry* ATTR_UNUSED(outbound))
7003b6c3722Schristos {
7013b6c3722Schristos    struct pythonmod_env* pe = (struct pythonmod_env*)qstate->env->modinfo[id];
7023b6c3722Schristos    struct pythonmod_qstate* pq = (struct pythonmod_qstate*)qstate->minfo[id];
7033b6c3722Schristos    PyObject* py_qstate, *res;
7043b6c3722Schristos    PyGILState_STATE gil = PyGILState_Ensure();
7053b6c3722Schristos 
7063b6c3722Schristos    if ( pq == NULL)
7073b6c3722Schristos    {
7083b6c3722Schristos       /* create qstate */
7093b6c3722Schristos       pq = qstate->minfo[id] = malloc(sizeof(struct pythonmod_qstate));
7107a540f2bSchristos       if(!pq) {
7117a540f2bSchristos 		log_err("pythonmod_operate: malloc failure for qstate");
7127a540f2bSchristos 		PyGILState_Release(gil);
7137a540f2bSchristos 		return;
7147a540f2bSchristos       }
7153b6c3722Schristos 
7163b6c3722Schristos       /* Initialize per query data */
71701049ae6Schristos       pq->data = PyDict_New();
7187a540f2bSchristos       if(!pq->data) {
7197a540f2bSchristos 		log_err("pythonmod_operate: malloc failure for query data dict");
7207a540f2bSchristos 		PyGILState_Release(gil);
7217a540f2bSchristos 		return;
7227a540f2bSchristos       }
7233b6c3722Schristos    }
7243b6c3722Schristos 
7253b6c3722Schristos    /* Call operate */
7263b6c3722Schristos    py_qstate = SWIG_NewPointerObj((void*) qstate, SWIGTYPE_p_module_qstate, 0);
7273b6c3722Schristos    res = PyObject_CallFunction(pe->func_operate, "iiOO", id, (int) event,
7283b6c3722Schristos 	py_qstate, pq->data);
7293b6c3722Schristos    if (PyErr_Occurred())
7303b6c3722Schristos    {
7313b6c3722Schristos       log_err("pythonmod: Exception occurred in function operate, event: %s", strmodulevent(event));
732f42d8de7Schristos       log_py_err();
7333b6c3722Schristos       qstate->ext_state[id] = module_error;
7343b6c3722Schristos    }
7353b6c3722Schristos    else if ((res == NULL)  || (!PyObject_IsTrue(res)))
7363b6c3722Schristos    {
7373b6c3722Schristos       log_err("pythonmod: python returned bad code, event: %s", strmodulevent(event));
7383b6c3722Schristos       qstate->ext_state[id] = module_error;
7393b6c3722Schristos    }
7403b6c3722Schristos    Py_XDECREF(res);
7413b6c3722Schristos    Py_XDECREF(py_qstate);
7423b6c3722Schristos 
7433b6c3722Schristos    PyGILState_Release(gil);
7443b6c3722Schristos }
7453b6c3722Schristos 
pythonmod_clear(struct module_qstate * qstate,int id)7463b6c3722Schristos void pythonmod_clear(struct module_qstate* qstate, int id)
7473b6c3722Schristos {
7483b6c3722Schristos    struct pythonmod_qstate* pq;
7493b6c3722Schristos    if (qstate == NULL)
7503b6c3722Schristos       return;
7513b6c3722Schristos 
7523b6c3722Schristos    pq = (struct pythonmod_qstate*)qstate->minfo[id];
753f42d8de7Schristos    verbose(VERB_ALGO, "pythonmod: clear, id: %d, pq:%p", id, pq);
7543b6c3722Schristos    if(pq != NULL)
7553b6c3722Schristos    {
7563b6c3722Schristos       PyGILState_STATE gil = PyGILState_Ensure();
7573b6c3722Schristos       Py_DECREF(pq->data);
7583b6c3722Schristos       PyGILState_Release(gil);
7593b6c3722Schristos       /* Free qstate */
7603b6c3722Schristos       free(pq);
7613b6c3722Schristos    }
7623b6c3722Schristos 
7633b6c3722Schristos    qstate->minfo[id] = NULL;
7643b6c3722Schristos }
7653b6c3722Schristos 
pythonmod_get_mem(struct module_env * env,int id)7663b6c3722Schristos size_t pythonmod_get_mem(struct module_env* env, int id)
7673b6c3722Schristos {
7683b6c3722Schristos    struct pythonmod_env* pe = (struct pythonmod_env*)env->modinfo[id];
769f42d8de7Schristos    verbose(VERB_ALGO, "pythonmod: get_mem, id: %d, pe:%p", id, pe);
7703b6c3722Schristos    if(!pe)
7713b6c3722Schristos       return 0;
7723b6c3722Schristos    return sizeof(*pe);
7733b6c3722Schristos }
7743b6c3722Schristos 
7753b6c3722Schristos /**
7763b6c3722Schristos  * The module function block
7773b6c3722Schristos  */
7783b6c3722Schristos static struct module_func_block pythonmod_block = {
7793b6c3722Schristos    "python",
7803b6c3722Schristos    &pythonmod_init, &pythonmod_deinit, &pythonmod_operate, &pythonmod_inform_super,
7813b6c3722Schristos    &pythonmod_clear, &pythonmod_get_mem
7823b6c3722Schristos };
7833b6c3722Schristos 
pythonmod_get_funcblock(void)7843b6c3722Schristos struct module_func_block* pythonmod_get_funcblock(void)
7853b6c3722Schristos {
7863b6c3722Schristos    return &pythonmod_block;
7873b6c3722Schristos }
788