diff options
Diffstat (limited to 'libreport/src/report-python')
26 files changed, 1348 insertions, 0 deletions
diff --git a/libreport/src/report-python/Makefile.am b/libreport/src/report-python/Makefile.am new file mode 100644 index 00000000..c1b37596 --- /dev/null +++ b/libreport/src/report-python/Makefile.am @@ -0,0 +1,43 @@ +pyreportexecdir = $(pyexecdir)/report + +pyreportexec_PYTHON = \ + __init__.py \ + accountmanager.py + +pyreportexec_LTLIBRARIES = _pyreport.la + +_pyreport_la_SOURCES = \ + reportmodule.c \ + problem_data.c \ + dump_dir.c \ + run_event.c \ + report.c \ + common.h +_pyreport_la_CPPFLAGS = \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ + -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ + -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ + -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + -DLOCALSTATEDIR='"$(localstatedir)"' \ + -DCONF_DIR=\"$(CONF_DIR)\" \ + -DVAR_RUN=\"$(VAR_RUN)\" \ + $(GLIB_CFLAGS) \ + $(PYTHON_CFLAGS) \ + -D_GNU_SOURCE \ + -Wall -Wwrite-strings -Werror +_pyreport_la_LDFLAGS = \ + -module \ + -avoid-version \ + -export-symbols-regex init_pyreport +_pyreport_la_LIBADD = \ + ../lib/libreport.la + +# report compat: + +pyreportioexecdir = $(pyexecdir)/report/io + +pyreportioexec_PYTHON = \ + io/__init__.py \ + io/GTKIO.py \ + io/NewtIO.py \ + io/TextIO.py diff --git a/libreport/src/report-python/README b/libreport/src/report-python/README new file mode 100644 index 00000000..1c9c3a27 --- /dev/null +++ b/libreport/src/report-python/README @@ -0,0 +1,44 @@ +Currently (2011-05), include/report/*.h are: + +dump_dir.h +event_config.h +problem_data.h +report.h +run_event.h + +and we wrap all of them except event_config.h. + +Python wrappers for C types and functions declared in include/report/FOO.h +should be implemented in corresponding FOO.c file in this directory. + +Their (C-level) declarations should go to common.h. + +Note that methods don't have to be declared in common.h: +they can be static functions inside FOO.c, and exposed to the rest +of the world via PyTypeObject instance. In FOO.c: + +static PyObject *p_method_name(PyObject *pself, PyObject *args) +... +static PyMethodDef p_FOO_methods[] = { +{ "method_name", p_method_name, METH_VARARGS, NULL } +... +}; +PyTypeObject p_FOO_type = { + .tp_methods = p_FOO_methods, +... +}; + +and only p_FOO_type needs to be declared in common.h. + +Similarly, (de)allocators, attr getters/setters also can be static functions +and be hooked into p_FOO_type. + +However, non-method functions can't be static. + + +File reportmodule.c contains the initialization function which should +initialize types (p_FOO_type objects) and hook up finctions from every +FOO.c so that they are usable from python code. + +Python wrappers for C constants (enums, defines) are created directly +by reportmodule.c. diff --git a/libreport/src/report-python/__init__.py b/libreport/src/report-python/__init__.py new file mode 100644 index 00000000..9efd5257 --- /dev/null +++ b/libreport/src/report-python/__init__.py @@ -0,0 +1,147 @@ +from _pyreport import * + + +#Compatibility with report package: + +import os + +SYSTEM_RELEASE_PATHS = ["/etc/system-release","/etc/redhat-release"] +####SYSTEM_RELEASE_DEPS = ["system-release", "redhat-release"] + +_hardcoded_default_product = "" +_hardcoded_default_version = "" + +####def getProduct_fromPRODUCT(): +#### try: +#### import product +#### return product.productName +#### except: +#### return "" + +####def getVersion_fromPRODUCT(): +#### try: +#### import product +#### return product.productVersion +#### except: +#### return "" + +####def getProduct_fromRPM(): +#### try: +#### import rpm +#### ts = rpm.TransactionSet() +#### for each_dep in SYSTEM_RELEASE_DEPS: +#### mi = ts.dbMatch('provides', each_dep) +#### for h in mi: +#### if h['name']: +#### return h['name'].split("-")[0].capitalize() +#### +#### return "" +#### except: +#### return "" + +####def getVersion_fromRPM(): +#### try: +#### import rpm +#### ts = rpm.TransactionSet() +#### for each_dep in SYSTEM_RELEASE_DEPS: +#### mi = ts.dbMatch('provides', each_dep) +#### for h in mi: +#### if h['version']: +#### return str(h['version']) +#### return "" +#### except: +#### return "" + +def getProduct_fromFILE(): + for each_path in SYSTEM_RELEASE_PATHS: + try: + file = open(each_path, "r") + content = file.read() + if content.startswith("Red Hat Enterprise Linux"): + return "Red Hat Enterprise Linux" + if content.startswith("Fedora"): + return "Fedora" + i = content.find(" release") + if i > -1: + return content[0:i] + except: + pass + return "" + +def getVersion_fromFILE(): + for each_path in SYSTEM_RELEASE_PATHS: + try: + file = open(each_path, "r") + content = file.read() + if content.find("Rawhide") > -1: + return "rawhide" + clist = content.split(" ") + i = clist.index("release") + return clist[i+1] + except: + pass + return "" + +def getProduct(): + ####product = getProduct_fromPRODUCT() + ####if product: + #### return product + product = getProduct_fromFILE() + if product: + return product + ####product = getProduct_fromRPM() + ####if product: + #### return product + return _hardcoded_default_product + +def getVersion(): + ####version = getVersion_fromPRODUCT() + ####if version: + #### return version + version = getVersion_fromFILE() + if version: + return version + ####version = getVersion_fromRPM() + ####if version: + #### return version + return _hardcoded_default_version + +def createAlertSignature(component, hashmarkername, hashvalue, summary, alertSignature): + pd = problem_data() + pd.add("component", component) + pd.add("hashmarkername", hashmarkername) + pd.add("duphash", hashvalue) + pd.add("reason", summary) + pd.add("description", alertSignature) + pd.add_basics() + + return pd + +# used in anaconda / python-meh +def createPythonUnhandledExceptionSignature(component, hashmarkername, hashvalue, summary, description, exnFileName): + pd = problem_data() + pd.add("component", component) + pd.add("hashmarkername", hashmarkername) + #cd.add("localhash", hashvalue) + pd.add("duphash", hashvalue) + pd.add("reason", summary) + pd.add("description", description) + #pd.add("product", getProduct()) + #pd.add("version", getVersion()) + pd.add_basics() # adds product and version + some other required field + # FIXME: how to handle files out of dump dir?? + #1 = flag BIN + pd.add("pythonUnhandledException", exnFileName, 1) + + return pd + +""" +def report(cd, io_unused): + state = run_event_state() + #state.logging_callback = logfunc + r = state.run_event_on_problem_data(cd, "report") + return r +""" + +def report(pd, io_unused): + result = report_problem(pd) diff --git a/libreport/src/report-python/accountmanager.py b/libreport/src/report-python/accountmanager.py new file mode 100644 index 00000000..db8ed117 --- /dev/null +++ b/libreport/src/report-python/accountmanager.py @@ -0,0 +1,6 @@ +""" + Compatibility with report package +""" + +class AccountManager: + pass diff --git a/libreport/src/report-python/common.h b/libreport/src/report-python/common.h new file mode 100644 index 00000000..713aa2f2 --- /dev/null +++ b/libreport/src/report-python/common.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2009 Abrt team. + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> + +#include "dump_dir.h" +#include "problem_data.h" +#include "run_event.h" +#include "report.h" + +/* exception object */ +extern PyObject *ReportError; + +/* type objects */ +extern PyTypeObject p_problem_data_type; +extern PyTypeObject p_dump_dir_type; +extern PyTypeObject p_run_event_state_type; + +/* python objects' struct defs */ +typedef struct { + PyObject_HEAD + struct dump_dir *dd; +} p_dump_dir; + +typedef struct { + PyObject_HEAD + problem_data_t *cd; +} p_problem_data; + +/* module-level functions */ +/* for include/report/dump_dir.h */ +PyObject *p_dd_opendir(PyObject *module, PyObject *args); +PyObject *p_dd_create(PyObject *module, PyObject *args); +PyObject *p_delete_dump_dir(PyObject *pself, PyObject *args); +/* for include/report/report.h */ +PyObject *p_report_problem_in_dir(PyObject *pself, PyObject *args); +PyObject *p_report_problem_in_memory(PyObject *pself, PyObject *args); +PyObject *p_report_problem(PyObject *pself, PyObject *args); diff --git a/libreport/src/report-python/dump_dir.c b/libreport/src/report-python/dump_dir.c new file mode 100644 index 00000000..e14e68d2 --- /dev/null +++ b/libreport/src/report-python/dump_dir.c @@ -0,0 +1,264 @@ +/* + On-disk storage of problem data + + Copyright (C) 2010 Abrt team + Copyright (C) 2010 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> +#include <structmember.h> + +#include <errno.h> +#include "common.h" + +/*** init/cleanup ***/ + +static PyObject * +p_dump_dir_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + p_dump_dir *self = (p_dump_dir *)type->tp_alloc(type, 0); + if (self) + self->dd = NULL; + return (PyObject *)self; +} + +static void +p_dump_dir_dealloc(PyObject *pself) +{ + p_dump_dir *self = (p_dump_dir*)pself; + dd_close(self->dd); + self->dd = NULL; + self->ob_type->tp_free(pself); +} + +//static int +//p_dump_dir_init(PyObject *pself, PyObject *args, PyObject *kwds) +//{ +// return 0; +//} + + +/*** methods ***/ + +/* void dd_close(struct dump_dir *dd); */ +static PyObject *p_dd_close(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; + dd_close(self->dd); + self->dd = NULL; + Py_RETURN_NONE; +} + +/* void dd_delete(struct dump_dir *dd); */ +static PyObject *p_dd_delete(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; +//Do we want to disallow delete() on non-opened dd? +// if (!self->dd) +// { +// PyErr_SetString(ReportError, "dump dir is not open"); +// return NULL; +// } + dd_delete(self->dd); + self->dd = NULL; + Py_RETURN_NONE; +} + +/* int dd_exist(struct dump_dir *dd, const char *path); */ +static PyObject *p_dd_exist(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; + if (!self->dd) + { + PyErr_SetString(ReportError, "dump dir is not open"); + return NULL; + } + const char *path; + if (!PyArg_ParseTuple(args, "s", &path)) + { + return NULL; + } + return Py_BuildValue("i", dd_exist(self->dd, path)); +} + +/* DIR *dd_init_next_file(struct dump_dir *dd); */ +//static PyObject *p_dd_init_next_file(PyObject *pself, PyObject *args); +/* int dd_get_next_file(struct dump_dir *dd, char **short_name, char **full_name); */ +//static PyObject *p_dd_get_next_file(PyObject *pself, PyObject *args); + +/* char* dd_load_text_ext(const struct dump_dir *dd, const char *name, unsigned flags); */ +/* char* dd_load_text(const struct dump_dir *dd, const char *name); */ +static PyObject *p_dd_load_text(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; + if (!self->dd) + { + PyErr_SetString(ReportError, "dump dir is not open"); + return NULL; + } + const char *name; + int flags = 0; + if (!PyArg_ParseTuple(args, "s|i", &name, &flags)) + { + return NULL; + } + char *val = dd_load_text_ext(self->dd, name, flags); + PyObject *obj = Py_BuildValue("s", val); /* NB: if val is NULL, obj is None */ + free(val); + return obj; +} + +/* void dd_save_text(struct dump_dir *dd, const char *name, const char *data); */ +static PyObject *p_dd_save_text(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; + if (!self->dd) + { + PyErr_SetString(ReportError, "dump dir is not open"); + return NULL; + } + const char *name; + const char *data; + if (!PyArg_ParseTuple(args, "ss", &name, &data)) + { + return NULL; + } + dd_save_text(self->dd, name, data); + Py_RETURN_NONE; +} + +/* void dd_save_binary(struct dump_dir *dd, const char *name, const char *data, unsigned size); */ +static PyObject *p_dd_save_binary(PyObject *pself, PyObject *args) +{ + p_dump_dir *self = (p_dump_dir*)pself; + if (!self->dd) + { + PyErr_SetString(ReportError, "dump dir is not open"); + return NULL; + } + const char *name; + const char *data; + unsigned size; + if (!PyArg_ParseTuple(args, "ssI", &name, &data, &size)) + { + return NULL; + } + dd_save_binary(self->dd, name, data, size); + Py_RETURN_NONE; +} + + +/*** attribute getters/setters ***/ + +static PyObject *get_name(PyObject *pself, void *unused) +{ + p_dump_dir *self = (p_dump_dir*)pself; + if (self->dd) + return Py_BuildValue("s", self->dd->dd_dirname); + Py_RETURN_NONE; +} + +//static PyObject *set_name(PyObject *pself, void *unused) +//{ +// PyErr_SetString(ReportError, "dump dir name is not settable"); +// Py_RETURN_NONE; +//} + + +/*** type object ***/ + +static PyMethodDef p_dump_dir_methods[] = { + /* method_name, func, flags, doc_string */ + { "close" , p_dd_close, METH_NOARGS, NULL }, + { "delete" , p_dd_delete, METH_NOARGS, NULL }, + { "exist" , p_dd_exist, METH_VARARGS, NULL }, + { "load_text" , p_dd_load_text, METH_VARARGS, NULL }, + { "save_text" , p_dd_save_text, METH_VARARGS, NULL }, + { "save_binary", p_dd_save_binary, METH_VARARGS, NULL }, + { NULL } +}; + +static PyGetSetDef p_dump_dir_getset[] = { + /* attr_name, getter_func, setter_func, doc_string, void_param */ + { (char*) "name", get_name, NULL /*set_name*/ }, + { NULL } +}; + +/* Support for "dd = dd_opendir(...); if [not] dd: ..." */ +static int p_dd_is_non_null(PyObject *pself) +{ + p_dump_dir *self = (p_dump_dir*)pself; + return self->dd != NULL; +} +static PyNumberMethods p_dump_dir_number_methods = { + .nb_nonzero = p_dd_is_non_null, +}; + +PyTypeObject p_dump_dir_type = { + PyObject_HEAD_INIT(NULL) + .tp_name = "report.dump_dir", + .tp_basicsize = sizeof(p_dump_dir), + /* Py_TPFLAGS_BASETYPE means "can be subtyped": */ + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = p_dump_dir_new, + .tp_dealloc = p_dump_dir_dealloc, + //.tp_init = p_dump_dir_init, + //.tp_members = p_dump_dir_members, + .tp_methods = p_dump_dir_methods, + .tp_as_number = &p_dump_dir_number_methods, + .tp_getset = p_dump_dir_getset, +}; + + +/*** module-level functions ***/ + +/* struct dump_dir *dd_opendir(const char *dir, int flags); */ +PyObject *p_dd_opendir(PyObject *module, PyObject *args) +{ + const char *dir; + int flags = 0; + if (!PyArg_ParseTuple(args, "s|i", &dir, &flags)) + return NULL; + p_dump_dir *new_dd = PyObject_New(p_dump_dir, &p_dump_dir_type); + if (!new_dd) + return NULL; + new_dd->dd = dd_opendir(dir, flags); + return (PyObject*)new_dd; +} + +/* struct dump_dir *dd_create(const char *dir, uid_t uid); */ +PyObject *p_dd_create(PyObject *module, PyObject *args) +{ + const char *dir; + int uid = -1; + if (!PyArg_ParseTuple(args, "s|i", &dir, &uid)) + return NULL; + p_dump_dir *new_dd = PyObject_New(p_dump_dir, &p_dump_dir_type); + if (!new_dd) + return NULL; + new_dd->dd = dd_create(dir, uid, 0640); + return (PyObject*)new_dd; +} + +/* void delete_dump_dir(const char *dirname); */ +PyObject *p_delete_dump_dir(PyObject *pself, PyObject *args) +{ + const char *dirname; + if (!PyArg_ParseTuple(args, "s", &dirname)) + return NULL; + delete_dump_dir(dirname); + Py_RETURN_NONE; +} diff --git a/libreport/src/report-python/io/GTKIO.py b/libreport/src/report-python/io/GTKIO.py new file mode 100644 index 00000000..4cc8766e --- /dev/null +++ b/libreport/src/report-python/io/GTKIO.py @@ -0,0 +1,11 @@ +""" + Compatibility with report package +""" + +class GTKIO: + def __init__(self, loginManager = None): + pass + +#class FailDialog(): +# def __init__(self, title, message): +# pass diff --git a/libreport/src/report-python/io/NewtIO.py b/libreport/src/report-python/io/NewtIO.py new file mode 100644 index 00000000..10eae284 --- /dev/null +++ b/libreport/src/report-python/io/NewtIO.py @@ -0,0 +1,7 @@ +""" + Compatibility with report package +""" + +class NewtIO: + def __init__(self, screen = None): + pass diff --git a/libreport/src/report-python/io/TextIO.py b/libreport/src/report-python/io/TextIO.py new file mode 100644 index 00000000..6162fb8b --- /dev/null +++ b/libreport/src/report-python/io/TextIO.py @@ -0,0 +1,6 @@ +""" + Compatibility with report package +""" + +class TextIO: + pass diff --git a/libreport/src/report-python/io/__init__.py b/libreport/src/report-python/io/__init__.py new file mode 100644 index 00000000..2ae28399 --- /dev/null +++ b/libreport/src/report-python/io/__init__.py @@ -0,0 +1 @@ +pass diff --git a/libreport/src/report-python/libreport-meh-test.py b/libreport/src/report-python/libreport-meh-test.py new file mode 100644 index 00000000..4ef24834 --- /dev/null +++ b/libreport/src/report-python/libreport-meh-test.py @@ -0,0 +1,31 @@ +#!/bin/env python + +from meh.dump import ReverseExceptionDump +from meh.handler import * +from meh.ui.gui import * + +class Config: + def __init__(self): + self.programName = "abrt" + self.programVersion = "2.0" + self.attrSkipList = [] + self.fileList = [] + self.config_value_one = 1 + self.config_value_two = 2 + + + +#meh.makeRHHandler("crash-test-meh", "1.0", Config()) +config = Config() +intf = GraphicalIntf(None) +handler = ExceptionHandler(config, intf, ReverseExceptionDump) +handler.install(None) + + +print "handler set up, about to divide by zero" + +zero = 0 +print 1 / zero + +print "should have crashed" + diff --git a/libreport/src/report-python/problem_data.c b/libreport/src/report-python/problem_data.c new file mode 100644 index 00000000..9067dead --- /dev/null +++ b/libreport/src/report-python/problem_data.c @@ -0,0 +1,147 @@ +/* + Copyright (C) 2010 Abrt team. + Copyright (C) 2010 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> +#include <structmember.h> + +#include <errno.h> +#include "common.h" + +static void +p_problem_data_dealloc(PyObject *pself) +{ + p_problem_data *self = (p_problem_data*)pself; + free_problem_data(self->cd); + self->cd = NULL; + self->ob_type->tp_free(pself); +} + +static PyObject * +p_problem_data_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + p_problem_data *self = (p_problem_data *)type->tp_alloc(type, 0); + if (self) + self->cd = new_problem_data(); + return (PyObject *)self; +} + +//static int +//p_problem_data_init(PyObject *pself, PyObject *args, PyObject *kwds) +//{ +// return 0; +//} + +/* +void add_to_problem_data_ext(problem_data_t *problem_data, + const char *name, + const char *content, + unsigned flags); +*/ +static PyObject *p_problem_data_add(PyObject *pself, PyObject *args) +{ + p_problem_data *self = (p_problem_data*)pself; + + const char *name; + const char *content; + int flags = 0; + if (!PyArg_ParseTuple(args, "ss|i", &name, &content, &flags)) + { + /* PyArg_ParseTuple raises the exception saying why it fails + * eg: TypeError: function takes exactly 2 arguments (1 given) + */ + return NULL; + } + add_to_problem_data_ext(self->cd, name, content, flags); + + /* every function returns PyObject, to return void we need to do this */ + Py_RETURN_NONE; +} + +/* struct problem_item *get_problem_data_item_or_NULL(problem_data_t *problem_data, const char *key); */ +static PyObject *p_get_problem_data_item(PyObject *pself, PyObject *args) +{ + p_problem_data *self = (p_problem_data*)pself; + const char *key; + if (!PyArg_ParseTuple(args, "s", &key)) + { + return NULL; + } + struct problem_item *ci = get_problem_data_item_or_NULL(self->cd, key); + if (ci == NULL) + { + Py_RETURN_NONE; + } + return Py_BuildValue("sI", ci->content, ci->flags); +} + +/* struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name); */ +static PyObject *p_create_dump_dir_from_problem_data(PyObject *pself, PyObject *args) +{ + p_problem_data *self = (p_problem_data*)pself; + const char *base_dir_name = NULL; + if (!PyArg_ParseTuple(args, "|s", &base_dir_name)) + { + return NULL; + } + p_dump_dir *new_dd = PyObject_New(p_dump_dir, &p_dump_dir_type); + if (!new_dd) + return NULL; + struct dump_dir *dd = create_dump_dir_from_problem_data(self->cd, base_dir_name); + if (!dd) + { + PyObject_Del((PyObject*)new_dd); + PyErr_SetString(ReportError, "Can't create the dump dir"); + return NULL; + } + new_dd->dd = dd; + return (PyObject*)new_dd; +} + +static PyObject *p_add_basics_to_problem_data(PyObject *pself, PyObject *always_null) +{ + p_problem_data *self = (p_problem_data*)pself; + add_basics_to_problem_data(self->cd); + + Py_RETURN_NONE; +} + + +//static PyMemberDef p_problem_data_members[] = { +// { NULL } +//}; + +static PyMethodDef p_problem_data_methods[] = { + /* method_name, func, flags, doc_string */ + { "add" , p_problem_data_add , METH_VARARGS }, + { "get" , p_get_problem_data_item , METH_VARARGS }, + { "create_dump_dir", p_create_dump_dir_from_problem_data, METH_VARARGS }, + { "add_basics", p_add_basics_to_problem_data, METH_NOARGS }, + { NULL } +}; + +PyTypeObject p_problem_data_type = { + PyObject_HEAD_INIT(NULL) + .tp_name = "report.problem_data", + .tp_basicsize = sizeof(p_problem_data), + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = p_problem_data_new, + .tp_dealloc = p_problem_data_dealloc, + //.tp_init = p_problem_data_init, + //.tp_members = p_problem_data_members, + .tp_methods = p_problem_data_methods, +}; diff --git a/libreport/src/report-python/py_report_test.py b/libreport/src/report-python/py_report_test.py new file mode 100644 index 00000000..e15044f8 --- /dev/null +++ b/libreport/src/report-python/py_report_test.py @@ -0,0 +1,7 @@ +import _pyreport + +pd = _pyreport.problem_data() +pd.add("foo", "bar") +pd.add("description", "python-libreport test bug") + +_pyreport.report(pd) diff --git a/libreport/src/report-python/pyreport.c b/libreport/src/report-python/pyreport.c new file mode 100644 index 00000000..0df47e78 --- /dev/null +++ b/libreport/src/report-python/pyreport.c @@ -0,0 +1,22 @@ +/* + Copyright (C) 2009 Abrt team. + Copyright (C) 2009 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "common.h" + +/* struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name); */ diff --git a/libreport/src/report-python/report.c b/libreport/src/report-python/report.c new file mode 100644 index 00000000..0bdd4076 --- /dev/null +++ b/libreport/src/report-python/report.c @@ -0,0 +1,59 @@ +/* + Copyright (C) 2010 Abrt team. + Copyright (C) 2010 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> + +#include "common.h" + +/* C: int report_problem_in_dir(const char *dirname, int flags); */ +PyObject *p_report_problem_in_dir(PyObject *pself, PyObject *args) +{ + const char *dirname; + int flags; + if (!PyArg_ParseTuple(args, "si", &dirname, &flags)) + { + return NULL; + } + int r = report_problem_in_dir(dirname, flags); + return Py_BuildValue("i", r); +} + +/* C: int report_problem_in_memory(problem_data_t *pd, int flags); */ +PyObject *p_report_problem_in_memory(PyObject *pself, PyObject *args) +{ + p_problem_data *pd; + int flags; + if (!PyArg_ParseTuple(args, "O!i", &p_problem_data_type, &pd, &flags)) + { + return NULL; + } + int r = report_problem_in_memory(pd->cd, flags); + return Py_BuildValue("i", r); +} + +/* C: int report_problem(problem_data_t *pd); */ +PyObject *p_report_problem(PyObject *pself, PyObject *args) +{ + p_problem_data *pd; + if (!PyArg_ParseTuple(args, "O!", &p_problem_data_type, &pd)) + { + return NULL; + } + int r = report_problem(pd->cd); + return Py_BuildValue("i", r); +} diff --git a/libreport/src/report-python/reportmodule.c b/libreport/src/report-python/reportmodule.c new file mode 100644 index 00000000..539c66aa --- /dev/null +++ b/libreport/src/report-python/reportmodule.c @@ -0,0 +1,95 @@ +/* + Copyright (C) 2010 Abrt team. + Copyright (C) 2010 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> + +#include "common.h" + +PyObject *ReportError; + +static PyMethodDef module_methods[] = { + /* method_name, func, flags, doc_string */ + /* for include/report/dump_dir.h */ + { "dd_opendir" , p_dd_opendir , METH_VARARGS }, + { "dd_create" , p_dd_create , METH_VARARGS }, + { "delete_dump_dir" , p_delete_dump_dir , METH_VARARGS }, + /* for include/report/report.h */ + { "report_problem_in_dir" , p_report_problem_in_dir , METH_VARARGS }, + { "report_problem_in_memory" , p_report_problem_in_memory, METH_VARARGS }, + { "report_problem" , p_report_problem , METH_VARARGS }, + { NULL } +}; + +#ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ +#define PyMODINIT_FUNC void +#endif +PyMODINIT_FUNC +init_pyreport(void) +{ + if (PyType_Ready(&p_problem_data_type) < 0) + { + printf("PyType_Ready(&p_problem_data_type) < 0\n"); + return; + } + if (PyType_Ready(&p_dump_dir_type) < 0) + { + printf("PyType_Ready(&p_dump_dir_type) < 0\n"); + return; + } + if (PyType_Ready(&p_run_event_state_type) < 0) + { + printf("PyType_Ready(&p_run_event_state_type) < 0\n"); + return; + } + + PyObject *m = Py_InitModule("_pyreport", module_methods); + //m = Py_InitModule3("_pyreport", module_methods, "Python wrapper for libreport"); + if (!m) + { + printf("m == NULL\n"); + return; + } + + /* init the exception object */ + ReportError = PyErr_NewException((char*) "_pyreport.error", NULL, NULL); + Py_INCREF(ReportError); + PyModule_AddObject(m, "error", ReportError); + + /* init type objects and constants */ + /* for include/report/problem_data.h */ + Py_INCREF(&p_problem_data_type); + PyModule_AddObject(m, "problem_data", (PyObject *)&p_problem_data_type); + PyModule_AddObject(m, "CD_FLAG_BIN" , Py_BuildValue("i", CD_FLAG_BIN )); + PyModule_AddObject(m, "CD_FLAG_TXT" , Py_BuildValue("i", CD_FLAG_TXT )); + PyModule_AddObject(m, "CD_FLAG_ISEDITABLE" , Py_BuildValue("i", CD_FLAG_ISEDITABLE )); + PyModule_AddObject(m, "CD_FLAG_ISNOTEDITABLE", Py_BuildValue("i", CD_FLAG_ISNOTEDITABLE)); + /* for include/report/dump_dir.h */ + Py_INCREF(&p_dump_dir_type); + PyModule_AddObject(m, "dump_dir", (PyObject *)&p_dump_dir_type); + PyModule_AddObject(m, "DD_FAIL_QUIETLY_ENOENT" , Py_BuildValue("i", DD_FAIL_QUIETLY_ENOENT )); + PyModule_AddObject(m, "DD_FAIL_QUIETLY_EACCES" , Py_BuildValue("i", DD_FAIL_QUIETLY_EACCES )); + PyModule_AddObject(m, "DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE", Py_BuildValue("i", DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE)); + /* for include/report/run_event.h */ + Py_INCREF(&p_run_event_state_type); + PyModule_AddObject(m, "run_event_state", (PyObject *)&p_run_event_state_type); + /* for include/report/report.h */ + PyModule_AddObject(m, "LIBREPORT_NOWAIT" , Py_BuildValue("i", LIBREPORT_NOWAIT )); + PyModule_AddObject(m, "LIBREPORT_WAIT" , Py_BuildValue("i", LIBREPORT_WAIT )); + PyModule_AddObject(m, "LIBREPORT_ANALYZE" , Py_BuildValue("i", LIBREPORT_ANALYZE )); + PyModule_AddObject(m, "LIBREPORT_RELOAD_DATA", Py_BuildValue("i", LIBREPORT_RELOAD_DATA)); +} diff --git a/libreport/src/report-python/run_event.c b/libreport/src/report-python/run_event.c new file mode 100644 index 00000000..50e3794e --- /dev/null +++ b/libreport/src/report-python/run_event.c @@ -0,0 +1,220 @@ +/* + Copyright (C) 2010 Abrt team. + Copyright (C) 2010 RedHat inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ +#include <Python.h> +#include <structmember.h> + +#include <errno.h> +#include "common.h" +#include "problem_data.h" +#include "run_event.h" + +typedef struct { + PyObject_HEAD + struct run_event_state *state; + PyObject *post_run_callback; + PyObject *logging_callback; +} p_run_event_state; + + +/*** init/cleanup ***/ + +static int post_run_callback(const char *dump_dir_name, void *param); +static char *logging_callback(char *log_line, void *param); + +static PyObject *p_run_event_state_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + p_run_event_state *self = (p_run_event_state *)type->tp_alloc(type, 0); + if (self) + { + self->state = new_run_event_state(); + self->state->post_run_callback = post_run_callback; + self->state->logging_callback = logging_callback; + self->state->post_run_param = self; + self->state->logging_param = self; + } + return (PyObject *)self; +} + +static void p_run_event_state_dealloc(PyObject *pself) +{ + p_run_event_state *self = (p_run_event_state*)pself; + free_run_event_state(self->state); + self->state = NULL; + Py_XDECREF(self->post_run_callback); + self->post_run_callback = NULL; + Py_XDECREF(self->logging_callback); + self->logging_callback = NULL; + self->ob_type->tp_free(pself); +} + +//static int +//p_run_event_state_init(PyObject *pself, PyObject *args, PyObject *kwds) +//{ +// return 0; +//} + + +/*** methods ***/ + +/* First, C-level callback helpers for run_event_on_FOO(): */ +static int post_run_callback(const char *dump_dir_name, void *param) +{ + PyObject *obj = (PyObject*)param; + PyObject *ret = PyObject_CallMethod(obj, (char*) "post_run_callback", (char*) "(s)", dump_dir_name); + int r = 0; + if (ret) + { + r = PyInt_AsLong(ret); + Py_DECREF(ret); + } + // TODO: handle exceptions: if (PyErr_Occurred()) ... + return r; +} +static char *logging_callback(char *log_line, void *param) +{ + PyObject *obj = (PyObject*)param; + PyObject *ret = PyObject_CallMethod(obj, (char*) "logging_callback", (char*) "(s)", log_line); + Py_XDECREF(ret); + // TODO: handle exceptions: if (PyErr_Occurred()) ... + return log_line; /* signaling to caller that we didnt consume the string */ +} + +/* int run_event_on_dir_name(struct run_event_state *state, const char *dump_dir_name, const char *event); */ +static PyObject *p_run_event_on_dir_name(PyObject *pself, PyObject *args) +{ + p_run_event_state *self = (p_run_event_state*)pself; + const char *dump_dir_name; + const char *event; + if (!PyArg_ParseTuple(args, "ss", &dump_dir_name, &event)) + { + return NULL; + } + int r = run_event_on_dir_name(self->state, dump_dir_name, event); + PyObject *obj = Py_BuildValue("i", r); + return obj; +} + +/* int run_event_on_problem_data(struct run_event_state *state, problem_data_t *data, const char *event); */ +static PyObject *p_run_event_on_problem_data(PyObject *pself, PyObject *args) +{ + p_run_event_state *self = (p_run_event_state*)pself; + p_problem_data *cd; + const char *event; + if (!PyArg_ParseTuple(args, "O!s", &p_problem_data_type, &cd, &event)) + { + return NULL; + } + int r = run_event_on_problem_data(self->state, cd->cd, event); + PyObject *obj = Py_BuildValue("i", r); + return obj; +} + +/* TODO: char *list_possible_events(struct dump_dir *dd, const char *dump_dir_name, const char *pfx); */ + + +/*** attribute getters/setters ***/ + +static PyObject *get_post_run_callback(PyObject *pself, void *unused) +{ + p_run_event_state *self = (p_run_event_state*)pself; + if (self->post_run_callback) + { + Py_INCREF(self->post_run_callback); + return self->post_run_callback; + } + Py_RETURN_NONE; +} + +static PyObject *get_logging_callback(PyObject *pself, void *unused) +{ + p_run_event_state *self = (p_run_event_state*)pself; + if (self->logging_callback) + { + Py_INCREF(self->logging_callback); + return self->logging_callback; + } + Py_RETURN_NONE; +} + +static int set_post_run_callback(PyObject *pself, PyObject *callback, void *unused) +{ + p_run_event_state *self = (p_run_event_state*)pself; +//WRONG: we aren't a Python function, calling convention is different +// PyObject *callback; +// if (!PyArg_ParseTuple(args, "O", &callback)) +// return -1; + if (!PyCallable_Check(callback)) + { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return -1; + } + Py_INCREF(callback); + Py_XDECREF(self->post_run_callback); + self->post_run_callback = callback; + return 0; +} + +static int set_logging_callback(PyObject *pself, PyObject *callback, void *unused) +{ + p_run_event_state *self = (p_run_event_state*)pself; + if (!PyCallable_Check(callback)) + { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return -1; + } + Py_INCREF(callback); + Py_XDECREF(self->logging_callback); + self->logging_callback = callback; + return 0; +} + + +/*** type object ***/ + +//static PyMemberDef p_run_event_state_members[] = { +// { NULL } +//}; + +static PyMethodDef p_run_event_state_methods[] = { + /* method_name, func, flags, doc_string */ + { "run_event_on_dir_name" , p_run_event_on_dir_name , METH_VARARGS }, + { "run_event_on_problem_data", p_run_event_on_problem_data, METH_VARARGS }, + { NULL } +}; + +static PyGetSetDef p_run_event_state_getset[] = { + /* attr_name, getter_func, setter_func, doc_string, void_param */ + { (char*) "post_run_callback", get_post_run_callback, set_post_run_callback }, + { (char*) "logging_callback" , get_logging_callback , set_logging_callback }, + { NULL } +}; + +PyTypeObject p_run_event_state_type = { + PyObject_HEAD_INIT(NULL) + .tp_name = "report.run_event_state", + .tp_basicsize = sizeof(p_run_event_state), + /* Py_TPFLAGS_BASETYPE means "can be subtyped": */ + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = p_run_event_state_new, + .tp_dealloc = p_run_event_state_dealloc, + //.tp_init = p_run_event_state_init, + //.tp_members = p_run_event_state_members, + .tp_methods = p_run_event_state_methods, + .tp_getset = p_run_event_state_getset, +}; diff --git a/libreport/src/report-python/test_dd_create b/libreport/src/report-python/test_dd_create new file mode 100755 index 00000000..4da29b11 --- /dev/null +++ b/libreport/src/report-python/test_dd_create @@ -0,0 +1,25 @@ +#!/usr/bin/python + +from report import * + +dd = dd_create("testdir") +print dd + +if dd: + print "dd is nonzero" +else: + print "dd is zero" + +print "name:", dd.name +print "closing" +dd.close() + +if dd: + print "dd is nonzero" +else: + print "dd is zero" + +# Should fail here +dd.name = "qwe" + +print "Done" diff --git a/libreport/src/report-python/test_full b/libreport/src/report-python/test_full new file mode 100755 index 00000000..107c4857 --- /dev/null +++ b/libreport/src/report-python/test_full @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys +from report import * + +def run_event_on_problem_data(cd, event, log_function = None): + dd = cd.create_dump_dir("/tmp") + dir_name = dd.name + print "Created dump_dir:", dir_name + dd.close() + run_state = run_event_state() + if log_function: # maybe if callable(log_function)? + run_state.logging_callback = log_function + print "Running event:", event + r = run_state.run_event_on_dir_name(dir_name, event) + print "Deleting:", dir_name + delete_dump_dir(dir_name) + return r; + +def log_function(line): + print "LOG:", line + +cd = problem_data() +cd.add("foo", "bar") +cd.add("analyzer", "baz", CD_FLAG_ISNOTEDITABLE) +r = run_event_on_problem_data(cd, "post-create", log_function) +print "Result:", r diff --git a/libreport/src/report-python/test_full2 b/libreport/src/report-python/test_full2 new file mode 100755 index 00000000..e6cfd4d9 --- /dev/null +++ b/libreport/src/report-python/test_full2 @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import sys +from report import * + +def log_function(line): + print "LOG:", line + +cd = problem_data() +cd.add("foo", "bar") +cd.add("analyzer", "baz", CD_FLAG_ISNOTEDITABLE) + +st = run_event_state() +st.logging_callback = log_function +r = st.run_event_on_problem_data(cd, "post-create") + +print "Result:", r diff --git a/libreport/src/report-python/test_problem_data b/libreport/src/report-python/test_problem_data new file mode 100644 index 00000000..16f1f9ae --- /dev/null +++ b/libreport/src/report-python/test_problem_data @@ -0,0 +1,21 @@ +#!/usr/bin/python + +from report import * + +cd = problem_data() +cd.add("foo", "bar") + +dd = cd.create_dump_dir() + +if dd: + print "dd is nonzero" +else: + print "dd is zero" + +print "closing" +dd.close() + +if dd: + print "dd is nonzero" +else: + print "dd is zero" diff --git a/libreport/src/report-python/test_problem_data2 b/libreport/src/report-python/test_problem_data2 new file mode 100644 index 00000000..3d3692b9 --- /dev/null +++ b/libreport/src/report-python/test_problem_data2 @@ -0,0 +1,10 @@ +#!/usr/bin/python + +from report import * + +cd = problem_data() +cd.add("foo", "bar") + +print "foo:", cd.get("foo") +print "nonexistent:", cd.get("nonexistent") +print "done" diff --git a/libreport/src/report-python/test_run_event_state b/libreport/src/report-python/test_run_event_state new file mode 100755 index 00000000..3e391407 --- /dev/null +++ b/libreport/src/report-python/test_run_event_state @@ -0,0 +1,13 @@ +#!/usr/bin/python + +from report import * + +def func(): + return 0 + +res = run_event_state() +print res +print res.post_run_callback +res.post_run_callback = func +res.logging_callback = func +print res.post_run_callback diff --git a/libreport/src/report-python/test_run_event_state1 b/libreport/src/report-python/test_run_event_state1 new file mode 100755 index 00000000..6c3584fe --- /dev/null +++ b/libreport/src/report-python/test_run_event_state1 @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys +from report import * + +def post_run_callback(dump_dir_name): + return 0 + +def logging_callback(line): + print "LOG:", line + return + +res = run_event_state() +res.post_run_callback = post_run_callback +res.logging_callback = logging_callback + +dd = dd_create("testdir") +if not dd: + sys.exit(1) +dd.save_text("analyzer", "foo") +dd.close() + +res.run_event_on_dir_name("testdir", "post-create") + +dd = dd_opendir("testdir") +dd.delete() +dd.close() diff --git a/libreport/src/report-python/test_setroubleshoot_example b/libreport/src/report-python/test_setroubleshoot_example new file mode 100755 index 00000000..74428f16 --- /dev/null +++ b/libreport/src/report-python/test_setroubleshoot_example @@ -0,0 +1,18 @@ +#!/usr/bin/python + +import report +import report.io +import report.io.GTKIO +import report.accountmanager + +accounts = report.accountmanager.AccountManager() + +signature = report.createAlertSignature("selinux-policy", + "setroubleshoot", + "self.siginfo.get_hash()", + "self.summary", + "content") + +rc = report.report(signature, report.io.GTKIO.GTKIO(accounts)) + +print "rc:", rc diff --git a/libreport/src/report-python/test_setroubleshoot_example2 b/libreport/src/report-python/test_setroubleshoot_example2 new file mode 100755 index 00000000..b712cda7 --- /dev/null +++ b/libreport/src/report-python/test_setroubleshoot_example2 @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import report +import report.io +import report.io.GTKIO +import report.accountmanager + +accounts = report.accountmanager.AccountManager() + +signature = report.createAlertSignature("selinux-policy", + "setroubleshoot", + "self.siginfo.get_hash()", + "self.summary", + "content") + +# Won't send log anywhere: +#rc = report.report(signature, report.io.GTKIO.GTKIO(accounts)) + +# report.report() + logging: +def logging_callback(line): + print "LOG:", line + return +state = report.run_event_state() +state.logging_callback = logging_callback +rc = state.run_event_on_problem_data(signature, "report") + +print "rc:", rc |