Update Red Hat Copyright Notices
[nbdkit.git] / plugins / python / errors.c
blobb59cbedbaf5b0137a2a0c3dbf865dcaede943bd7
1 /* nbdkit
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 #include <config.h>
35 #include <stdio.h>
36 #include <stdlib.h>
38 #include "cleanup.h"
40 #include "plugin.h"
42 /* This is the fallback in case we cannot get the full traceback. */
43 static void
44 print_python_error (const char *callback, PyObject *error)
46 PyObject *error_str;
47 CLEANUP_FREE char *error_cstr = NULL;
49 error_str = PyObject_Str (error);
50 error_cstr = python_to_string (error_str);
51 nbdkit_error ("%s: %s: error: %s",
52 script, callback,
53 error_cstr ? error_cstr : "<unknown>");
54 Py_DECREF (error_str);
57 /* Convert the Python traceback to a string and call nbdkit_error.
58 * https://stackoverflow.com/a/15907460/7126113
60 static int
61 print_python_traceback (const char *callback,
62 PyObject *type, PyObject *error, PyObject *traceback)
64 PyObject *module_name, *traceback_module, *format_exception_fn, *rv,
65 *traceback_str;
66 CLEANUP_FREE char *traceback_cstr = NULL;
68 module_name = PyUnicode_FromString ("traceback");
69 traceback_module = PyImport_Import (module_name);
70 Py_DECREF (module_name);
72 /* couldn't 'import traceback' */
73 if (traceback_module == NULL)
74 return -1;
76 format_exception_fn = PyObject_GetAttrString (traceback_module,
77 "format_exception");
78 if (format_exception_fn == NULL)
79 return -1;
80 if (!PyCallable_Check (format_exception_fn))
81 return -1;
83 rv = PyObject_CallFunctionObjArgs (format_exception_fn,
84 type, error, traceback, NULL);
85 if (rv == NULL)
86 return -1;
87 traceback_str = PyUnicode_Join (NULL, rv);
88 Py_DECREF (rv);
89 traceback_cstr = python_to_string (traceback_str);
90 if (traceback_cstr == NULL) {
91 Py_DECREF (traceback_str);
92 return -1;
95 nbdkit_error ("%s: %s: error: %s",
96 script, callback,
97 traceback_cstr);
98 Py_DECREF (traceback_str);
100 /* This means we succeeded in calling nbdkit_error. */
101 return 0;
105 check_python_failure (const char *callback)
107 if (PyErr_Occurred ()) {
108 PyObject *type, *error, *traceback;
110 PyErr_Fetch (&type, &error, &traceback);
111 PyErr_NormalizeException (&type, &error, &traceback);
113 /* Try to print the full traceback. */
114 if (print_python_traceback (callback, type, error, traceback) == -1) {
115 /* Couldn't do that, so fall back to converting the Python error
116 * to a string.
118 print_python_error (callback, error);
121 /* In all cases this returns -1 to indicate that a Python error
122 * occurred.
124 return -1;
126 return 0;