diff options
author | Jiri Moskovcak <jmoskovc@redhat.com> | 2010-06-10 09:10:09 +0200 |
---|---|---|
committer | Jiri Moskovcak <jmoskovc@redhat.com> | 2010-06-10 09:10:09 +0200 |
commit | f1c1b935b89963d18552e0d0b7e81fb2341a61ea (patch) | |
tree | 7f8b6248a23e41dc5eb6c21f8af276c604f04128 | |
parent | 11839b1f6e6e12731f3b779f554d4f2997a23c7d (diff) | |
parent | 5a8e8a4678b380026bee7b6838fd11272112c9f3 (diff) | |
download | abrt-f1c1b935b89963d18552e0d0b7e81fb2341a61ea.tar.gz abrt-f1c1b935b89963d18552e0d0b7e81fb2341a61ea.tar.xz abrt-f1c1b935b89963d18552e0d0b7e81fb2341a61ea.zip |
Merge branch 'master' of ssh://git.fedorahosted.org/git/abrt
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | abrt.spec | 1 | ||||
-rw-r--r-- | lib/Utils/Makefile.am | 3 | ||||
-rw-r--r-- | lib/Utils/hooklib.cpp (renamed from src/Hooks/hooklib.cpp) | 0 | ||||
-rw-r--r-- | lib/Utils/hooklib.h (renamed from src/Hooks/hooklib.h) | 0 | ||||
-rw-r--r-- | po/it.po | 200 | ||||
-rwxr-xr-x | scripts/abrt-bz-dupchecker | 21 | ||||
-rw-r--r-- | src/Daemon/Daemon.cpp | 5 | ||||
-rw-r--r-- | src/Daemon/Makefile.am | 3 | ||||
-rw-r--r-- | src/Daemon/dumpsocket.cpp | 573 | ||||
-rw-r--r-- | src/Daemon/dumpsocket.h | 81 | ||||
-rw-r--r-- | src/Hooks/Makefile.am | 28 | ||||
-rw-r--r-- | src/Hooks/abrt-hook-python.cpp | 160 | ||||
-rw-r--r-- | src/Hooks/abrt_exception_handler.py.in | 25 |
14 files changed, 797 insertions, 305 deletions
@@ -51,13 +51,11 @@ src/CLI/abrt-cli src/utils/abrt-backtrace lib/Utils/backtrace_parser.c lib/Utils/backtrace_parser.output -src/Backtrace/*.bt src/Daemon/abrtd src/Gui/abrt.desktop src/Hooks/abrt_exception_handler.py src/Hooks/dumpoops src/Hooks/abrt-hook-ccpp -src/Hooks/abrt-hook-python scripts/abrt-rate-backtrace stamp-h1 x86_64/ @@ -447,7 +447,6 @@ fi %files addon-python %defattr(-,root,root,-) %config(noreplace) %{_sysconfdir}/%{name}/plugins/Python.conf -%attr(4755, abrt, abrt) %{_libexecdir}/abrt-hook-python %{_libdir}/%{name}/libPython.so* %{python_site}/*.py* %{python_site}/abrt.pth diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am index 13144f68..f9979ec0 100644 --- a/lib/Utils/Makefile.am +++ b/lib/Utils/Makefile.am @@ -26,7 +26,8 @@ libABRTUtils_la_SOURCES = \ ABRTException.cpp \ backtrace.h backtrace.c \ backtrace_parser.y \ - strbuf.h strbuf.c + strbuf.h strbuf.c \ + hooklib.h hooklib.cpp libABRTUtils_la_CPPFLAGS = \ -Wall -Werror \ -I$(srcdir)/../../inc \ diff --git a/src/Hooks/hooklib.cpp b/lib/Utils/hooklib.cpp index 0c00e75f..0c00e75f 100644 --- a/src/Hooks/hooklib.cpp +++ b/lib/Utils/hooklib.cpp diff --git a/src/Hooks/hooklib.h b/lib/Utils/hooklib.h index 1651204f..1651204f 100644 --- a/src/Hooks/hooklib.h +++ b/lib/Utils/hooklib.h @@ -10,10 +10,10 @@ # Andrea La Fauci <andrea.lafauci@weproudlymanage.com>, 2010. msgid "" msgstr "" -"Project-Id-Version: abrt-fed14\n" +"Project-Id-Version: ABRT\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" "POT-Creation-Date: 2010-06-09 15:38+0200\n" -"PO-Revision-Date: 2010-05-28 10:59+1000\n" +"PO-Revision-Date: 2010-06-10 14:42+1000\n" "Last-Translator: \n" "Language-Team: <it@li.org>\n" "MIME-Version: 1.0\n" @@ -22,63 +22,61 @@ msgstr "" "X-Generator: KBabel 1.11.4\n" #: lib/Plugins/Catcut.cpp:61 -#, fuzzy msgid "send_string: URL not specified" -msgstr "FileTransfer: URL non specificato" +msgstr "send_string: URL non specificato" #: lib/Plugins/Catcut.cpp:77 lib/Plugins/Catcut.cpp:114 -#, fuzzy, c-format +#, c-format msgid "Sending failed, try it again: %s" -msgstr "Invio archivio %s su %s" +msgstr "Invio fallito, riprova: %s" #: lib/Plugins/Catcut.cpp:95 -#, fuzzy msgid "send_file: URL not specified" -msgstr "FileTransfer: URL non specificato" +msgstr "send_file: URL non specificato" #: lib/Plugins/Catcut.cpp:99 -#, fuzzy, c-format +#, c-format msgid "Sending file %s to %s" -msgstr "Invio archivio %s su %s" +msgstr "Invio file %s a %s in corso" #: lib/Plugins/Catcut.cpp:325 -#, fuzzy, c-format +#, c-format msgid "New bug id: %s" -msgstr "Nuovo id del bug: %i" +msgstr "Nuovo id del bug: %s" #: lib/Plugins/Catcut.cpp:366 #, c-format msgid "error returned by requestUpload: %s" -msgstr "" +msgstr "errore ritornato da requestUpload: %s" #: lib/Plugins/Catcut.cpp:371 #, c-format msgid "error returned by requestUpload: %d" -msgstr "" +msgstr "errore ritornato da requestUpload: %d" #: lib/Plugins/Catcut.cpp:377 msgid "no URL returned by requestUpload, and no errno" -msgstr "" +msgstr "nessun URL ritornato da requestUpload, e nessun errno" #: lib/Plugins/Catcut.cpp:382 #, c-format msgid "requestUpload returned URL: %s" -msgstr "" +msgstr "URL ritornato da requestUpload: %s" #: lib/Plugins/Catcut.cpp:402 #, c-format msgid "Attaching (text): %s" -msgstr "" +msgstr "Inserimento (testo) in corso: %s" #: lib/Plugins/Catcut.cpp:413 lib/Plugins/Catcut.cpp:431 #, c-format msgid "rebased URL: %s" -msgstr "" +msgstr "URL modificato: %s" #: lib/Plugins/Catcut.cpp:420 #, c-format msgid "Attaching binary: %s" -msgstr "" +msgstr "Inserimento binario: %s" #: lib/Plugins/Catcut.cpp:460 lib/Plugins/Bugzilla.cpp:655 msgid "Creating new bug..." @@ -96,27 +94,24 @@ msgstr "Invio archivio %s su %s" #: lib/Plugins/TicketUploader.cpp:130 #, c-format msgid "Sending failed, trying again. %s" -msgstr "" +msgstr "Invio fallito, riprovo ancora. %s" #: lib/Plugins/TicketUploader.cpp:192 -#, fuzzy msgid "Creating a TicketUploader report..." -msgstr "Creazione ed invio di un report in corso..." +msgstr "Creazione di una notifica TicketUploader in corso..." #: lib/Plugins/rhfastcheck.cpp:71 -#, fuzzy msgid "Creating a signature..." -msgstr "Creazione ed invio di un report in corso..." +msgstr "Creazione di una firma in corso..." #: lib/Plugins/rhticket.cpp:222 -#, fuzzy msgid "Creating a new case..." -msgstr "Creazione nuovo bug..." +msgstr "Creazione di un nuovo caso..." #: lib/Utils/make_descr.cpp:296 #, c-format msgid "Binary file %s will not be reported" -msgstr "" +msgstr "Il file binario %s non verrà riportato" #: src/CLI/CLI.cpp:68 #, c-format @@ -129,6 +124,13 @@ msgid "" "\tCrash Time : %s\n" "\tCrash Count: %s\n" msgstr "" +"%u.\n" +"\tUID : %s\n" +"\tUUID : %s\n" +"\tPackage : %s\n" +"\tExecutable : %s\n" +"\tCrash Time : %s\n" +"\tCrash Count: %s\n" #: src/CLI/CLI.cpp:154 #, c-format @@ -150,126 +152,142 @@ msgid "" "\tunique UUID prefix - the crash with matching UUID will be acted upon\n" "\t@N - N'th crash (as displayed by --get-list-full) will be acted upon\n" msgstr "" +"Usage: %s [OPTION]\n" +"\n" +"Avvio:\n" +"\t-V, --version\t\tmostra la versione di %s ed esci\n" +"\t-?, --help\t\tstampa questo aiuto\n" +"\n" +"Azioni:\n" +"\t--get-list\t\tstampa elenco dei crash non ancora riportati\n" +"\t--get-list-full\t\tstampa elenco di tutti i crash\n" +"\t--report CRASH_ID\tcrea ed invia riporto\n" +"\t--report-always CRASH_ID crea ed invia riporto senza chiederlo\n" +"\t--delete CRASH_ID\trimuovi il crash\n" +"CRASH_ID possono essere:\n" +"\tUID:UUID pair,\n" +"\tprefisso UUID unico - il crash con un UUID corrispondente verrà esaminato\n" +"\t@N - N'th crash (come mostrato da --get-list-full) verrà esaminato\n" #: src/CLI/CLI.cpp:198 msgid "You must specify exactly one operation." -msgstr "" +msgstr "Specificare esattamente una operazione." #: src/CLI/report.cpp:179 #, c-format msgid "# This field is read only.\n" -msgstr "" +msgstr "# Questo campo è di sola lettura.\n" #: src/CLI/report.cpp:199 msgid "# Describe the circumstances of this crash below." -msgstr "" +msgstr "# Descrivere qui di seguito le circostanza di questo crash." #: src/CLI/report.cpp:201 msgid "# How to reproduce the crash?" -msgstr "" +msgstr "# Come riprodurre il crash?" #: src/CLI/report.cpp:203 msgid "" "# Backtrace\n" "# Check that it does not contain any sensitive data such as passwords." msgstr "" +"# Backtrace\n" +"# Controllare che non contenga alcun dato sensibile come ad esempio le password." #: src/CLI/report.cpp:205 -#, fuzzy msgid "# Architecture" -msgstr "Architettura" +msgstr "# Architettura" #: src/CLI/report.cpp:206 -#, fuzzy msgid "# Command line" -msgstr "Cmdline" +msgstr "# linea di comando" #: src/CLI/report.cpp:207 -#, fuzzy msgid "# Component" -msgstr "Componente" +msgstr "# Componente" #: src/CLI/report.cpp:208 msgid "# Core dump" -msgstr "" +msgstr "# Core dump" #: src/CLI/report.cpp:209 -#, fuzzy msgid "# Executable" -msgstr "Eseguibile" +msgstr "# Eseguibile" #: src/CLI/report.cpp:210 msgid "# Kernel version" -msgstr "" +msgstr "# versione del kernel" #: src/CLI/report.cpp:211 -#, fuzzy msgid "# Package" -msgstr "Pacchetto" +msgstr "# Pacchetto" #: src/CLI/report.cpp:212 msgid "# Reason of crash" -msgstr "" +msgstr "# Motivo del crash" #: src/CLI/report.cpp:213 msgid "# Release string of the operating system" -msgstr "" +msgstr "# Stringa della release del sistema operativo" #: src/CLI/report.cpp:323 msgid "Terminal is dumb but no VISUAL nor EDITOR defined." -msgstr "" +msgstr "Il Terminale è su dumb ma non è stato definito alcun VISUAL o EDITOR." #: src/CLI/report.cpp:411 msgid "" "\n" "The report has been updated." msgstr "" +"\n" +"La notifica è stata aggiornata." #: src/CLI/report.cpp:413 msgid "" "\n" "No changes were detected in the report." msgstr "" +"\n" +"Nessuna modifica è stata rilevata nel report." #: src/CLI/report.cpp:628 #, c-format msgid "Wrong settings were detected for plugin %s.\n" -msgstr "" +msgstr "Rilevate impostazioni errate per il plugin %s.\n" #: src/CLI/report.cpp:632 msgid "Enter your login: " -msgstr "" +msgstr "Inserire il login:" #: src/CLI/report.cpp:638 msgid "Enter your password: " -msgstr "" +msgstr "Inserire la password:" #: src/CLI/report.cpp:681 -#, fuzzy msgid "Reporting..." -msgstr "Report" +msgstr "Notifica in corso..." #: src/CLI/report.cpp:700 #, c-format msgid "Report using %s? [y/N]: " -msgstr "" +msgstr "Notifica utilizzando %s? [s/N]: " #: src/CLI/report.cpp:703 msgid "Skipping..." -msgstr "" +msgstr "Omissione in corso..." #: src/CLI/report.cpp:720 #, c-format msgid "Crash reported via %d plugins (%d errors)\n" -msgstr "" +msgstr "Crash notificato tramite %d plugin (%d errori)\n" #: src/Daemon/CommLayerServerDBus.cpp:234 msgid "Comment is too long" -msgstr "" +msgstr "Il commento è troppo lungo" #: src/Daemon/CommLayerServerDBus.cpp:238 msgid "'How to reproduce' is too long" -msgstr "" +msgstr "'How to reproduce' è troppo lungo" #: src/Gui/ABRTExceptions.py:6 msgid "Another client is already running, trying to wake it." @@ -277,8 +295,7 @@ msgstr "Un altro client è già in esecuzione, tento il ripristino." #: src/Gui/ABRTExceptions.py:13 msgid "Got unexpected data from daemon (is the database properly updated?)." -msgstr "" -"Ricevuti dati inattesi dal demone (il database è aggiornato correttamente?)." +msgstr "Ricevuti dati inattesi dal demone (il database è aggiornato correttamente?)." #: src/Gui/ABRTPlugin.py:62 msgid "Not loaded plugins" @@ -577,28 +594,25 @@ msgid "Error getting the report: %s" msgstr "Errore nell'ottenere il report: %s" #: src/Gui/ConfBackend.py:77 -#, fuzzy msgid "Can't connect to Gnome Keyring daemon" -msgstr "Impossibile connettersi a dbus del sistema" +msgstr "Impossibile connettersi al demone Gnome Keyring" #: src/Gui/ConfBackend.py:83 msgid "Can't get default keyring" -msgstr "" +msgstr "Impossibile acquisire il keyring predefinito" #: src/Gui/ConfBackend.py:102 src/Gui/ConfBackend.py:118 -msgid "" -"Access to gnome-keyring has been denied, plugins settings won't be saved." -msgstr "" +msgid "Access to gnome-keyring has been denied, plugins settings won't be saved." +msgstr "L'accesso al gnome-keyring è stato negato, le impostazioni dei plugin non saranno salvati." #: src/Gui/ConfBackend.py:152 #, python-format -msgid "" -"Access to gnome-keyring has been denied, can't load the settings for %s!" -msgstr "" +msgid "Access to gnome-keyring has been denied, can't load the settings for %s!" +msgstr "L'accesso al gnome-keyring è stato negato, impossibile caricare le impostazioni per %s!." #: src/Gui/ConfBackend.py:205 msgid "Access to gnome-keyring has been denied, can't load settings" -msgstr "" +msgstr "L'accesso al gnome-keyring è stato negato, impossibile caricare le impostazioni" #: src/Gui/dialogs.glade:7 msgid "Report done" @@ -610,25 +624,25 @@ msgstr "Log" #: src/Gui/PluginsSettingsDialog.py:24 msgid "Can't load gui description for SettingsDialog!" -msgstr "" +msgstr "Impossibile caricare la descrizione della gui per SettingsDialog!" #: src/Gui/PluginsSettingsDialog.py:41 -#, fuzzy msgid "Name" -msgstr "Nome:" +msgstr "Nome" #: src/Gui/PluginsSettingsDialog.py:148 msgid "Please select a plugin from the list to edit it's options." -msgstr "" +msgstr "Selezionare un plugin dall'elenco per modificare le opzioni." #: src/Gui/PluginsSettingsDialog.py:156 -#, fuzzy, python-format +#, python-format msgid "" "Error while opening plugin settings UI: \n" "\n" "%s" msgstr "" -"Errore durante il caricamento della dumplist.\n" +"Errore durante l'apertura della UI per le impostazioni del plugin:\n" +"\n" "%s" #: src/Gui/PluginSettingsUI.py:17 @@ -683,8 +697,7 @@ msgstr "<span fgcolor=\"blue\">Causa:</span>" #: src/Gui/report.glade:331 msgid "I checked backtrace and removed sensitive data (passwords, etc)" -msgstr "" -"Ho controllato il backtrace ed ho rimosso i dati sensibili (password, etc)" +msgstr "Ho controllato il backtrace ed ho rimosso i dati sensibili (password, etc)" #: src/Gui/report.glade:369 src/Gui/CReporterAssistant.py:711 msgid "<b>Backtrace</b>" @@ -839,9 +852,8 @@ msgid "GPG Keys" msgstr "Chiavi GPG" #: src/Gui/CReporterAssistant.py:273 -#, fuzzy msgid "You should check backtrace for sensitive data" -msgstr "E' necessario verificare il backtrace per trovare dati sensibili" +msgstr "E' necessario verificare il backtrace per i dati sensibili" #: src/Gui/CReporterAssistant.py:274 msgid "You must agree with sending the backtrace" @@ -924,8 +936,7 @@ msgstr "" "problema?" #: src/Gui/CReporterAssistant.py:611 -msgid "" -"Are there any comment you'd like to share with the software maintainers?" +msgid "Are there any comment you'd like to share with the software maintainers?" msgstr "Condividere alcun commento con i manutentori software?" #: src/Gui/CReporterAssistant.py:630 @@ -945,8 +956,7 @@ msgid "Confirm and send report" msgstr "Conferma ed invia il riporto" #: src/Gui/CReporterAssistant.py:680 -msgid "" -"Below is a summary of your bug report. Please click 'Apply' to submit it." +msgid "Below is a summary of your bug report. Please click 'Apply' to submit it." msgstr "" "Di seguito viene riportato un sommario del bug report. Fare clic su " "'Applica' per inviarlo." @@ -992,9 +1002,8 @@ msgid "Click to view ..." msgstr "Clicca per visualizzare ..." #: src/Gui/CReporterAssistant.py:726 -#, fuzzy msgid "<b>Steps to reproduce:</b>" -msgstr "<b>Fasi da riprodurre:</b>" +msgstr "<b>Fasi da eseguire:</b>" #: src/Gui/CReporterAssistant.py:747 msgid "<b>Comments:</b>" @@ -1005,9 +1014,8 @@ msgid "No comment provided!" msgstr "Nessun commento fornito!" #: src/Gui/CReporterAssistant.py:786 -#, fuzzy msgid "Finished sending the bug report" -msgstr "Termina l'invio del bug report" +msgstr "Invio del bug report terminato" #: src/Gui/CReporterAssistant.py:790 msgid "<b>Bug reports:</b>" @@ -1015,19 +1023,18 @@ msgstr "<b>Bug Report:</b>" #: src/Gui/settings_wizard.glade:7 msgid "Wrong Settings Detected" -msgstr "" +msgstr "Impostazioni errate rilevate" #: src/Gui/settings_wizard.glade:40 msgid "" "Wrong settings detected for some of the enabled reporter plugins, please use " "the buttons below to open respective configuration and fix it before you " "proceed, otherwise the reporting process can fail.\n" -msgstr "" +msgstr "Impostazioni errate rilevate per alcuni dei reporter plugin abilitati, usare i pulsanti sotto riportati per aprire la rispettiva configurazione e correggerla prima di procedere, in caso contrario il processo di notifica può fallire.\n" #: src/Gui/settings_wizard.glade:71 -#, fuzzy msgid "<b>Do you want to continue?</b>" -msgstr "<b>Dove vuoi segnalare questo incidente?</b>" +msgstr "<b>Desideri continuare?</b>" #: src/Applet/Applet.cpp:88 #, c-format @@ -1185,16 +1192,3 @@ msgstr "Esecuzione di sosreport: %s" msgid "Done running sosreport" msgstr "Esecuzione di sosreport completata" -#, fuzzy -#~ msgid "" -#~ "Thank you for your bug report. It has been successfully submitted. You " -#~ "can see the results below." -#~ msgstr "" -#~ "Grazie per l'invio del bug report. Il suo invio ha avuto successo. Per " -#~ "visualizzare il bug report online usare il seguente indirizzo web:" - -#~ msgid "View and report application crashes" -#~ msgstr "Visualizza e riporta i crash applicativi" - -#~ msgid "Not reported" -#~ msgstr "Non riportato" diff --git a/scripts/abrt-bz-dupchecker b/scripts/abrt-bz-dupchecker index 89e13281..65e11531 100755 --- a/scripts/abrt-bz-dupchecker +++ b/scripts/abrt-bz-dupchecker @@ -54,7 +54,7 @@ bz = RHBugzilla() bz.connect(options.bugzilla) bz.login(options.user, options.password) -buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash'}) +buginfos = bz.query({'status_whiteboard_type':'allwordssubstr','status_whiteboard':'abrt_hash', 'product':'Fedora'}) print "{0} bugs found.".format(len(buginfos)) @@ -122,7 +122,7 @@ for buginfo in buginfos: if not downloaded: continue - command = ["./abrt-backtrace"] + command = ["abrt-backtrace"] command.append(filename) command.append("--single-thread") command.append("--frame-depth=5") @@ -178,7 +178,7 @@ for backtrace, components in database.items(): # Get the component owner owner = "Failed to get component owner" try: - component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/packages/name/{0}?tg_format=json".format(component))) + component_info = json.load(urllib.urlopen("https://admin.fedoraproject.org/pkgdb/acls/name/{0}?tg_format=json".format(component))) component_packages = component_info['packageListings'] component_f12 = filter(lambda x:x["collection"]["version"]=="12", component_packages) if len(component_f12) == 1: @@ -191,7 +191,7 @@ for backtrace, components in database.items(): # Close all bugs where it is appropriate. if options.close: - LIMIT = 1000 + LIMIT = 10000 # infinite counter = 0 for (component, owner, bugitems, backtrace) in dups: # Find the master bug item @@ -212,15 +212,24 @@ if options.close: else: return -1 + # Sort the duplicates by the number of comments. + # Select the bug with the highest number of comments as the master bug. + # All other bugs without user comments will be closed as a duplicate of + # the master bug. sorteditems = sorted(bugitems, commentCmp) - master = sorteditems[0] + + # Check the master bug status AGAIN to make sure the bug is still opened. + bug = bz.getbug(int(master['id'])) + if not bug.bug_status in ["NEW", "ASSIGNED"]: + continue + for item in sorteditems[1:]: if item['comments'] > 2: continue - bug = bz.getbug(int(item['id'])) # Check the bug status AGAIN to make sure the bug is still opened. + bug = bz.getbug(int(item['id'])) if not bug.bug_status in ["NEW", "ASSIGNED"]: continue diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp index 3d8df570..d79d90a4 100644 --- a/src/Daemon/Daemon.cpp +++ b/src/Daemon/Daemon.cpp @@ -41,6 +41,7 @@ #include "CrashWatcher.h" #include "DebugDump.h" #include "Daemon.h" +#include "dumpsocket.h" using namespace std; @@ -848,6 +849,9 @@ int main(int argc, char** argv) throw 1; pidfile_created = true; + /* Open socket to receive new crashes. */ + dumpsocket_init(); + /* Note: this already may process a few dbus messages, * therefore it should be the last thing to initialize. */ @@ -899,6 +903,7 @@ int main(int argc, char** argv) /* Error or INT/TERM. Clean up, in reverse order. * Take care to not undo things we did not do. */ + dumpsocket_shutdown(); if (pidfile_created) unlink(VAR_RUN_PIDFILE); if (lockfile_created) diff --git a/src/Daemon/Makefile.am b/src/Daemon/Makefile.am index 382f104f..56292150 100644 --- a/src/Daemon/Makefile.am +++ b/src/Daemon/Makefile.am @@ -10,7 +10,8 @@ abrtd_SOURCES = \ CommLayerServer.h CommLayerServer.cpp \ CommLayerServerDBus.h CommLayerServerDBus.cpp \ Daemon.h Daemon.cpp \ - Settings.h Settings.cpp + Settings.h Settings.cpp \ + dumpsocket.h dumpsocket.cpp abrtd_CPPFLAGS = \ -I$(srcdir)/../../inc \ -I$(srcdir)/../../lib/Utils \ diff --git a/src/Daemon/dumpsocket.cpp b/src/Daemon/dumpsocket.cpp new file mode 100644 index 00000000..f1171ea8 --- /dev/null +++ b/src/Daemon/dumpsocket.cpp @@ -0,0 +1,573 @@ +/* + Copyright (C) 2010 ABRT team + + 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 "dumpsocket.h" +#include "abrtlib.h" +#include <glib.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> +#include "DebugDump.h" +#include "CrashTypes.h" +#include "ABRTException.h" +#include "hooklib.h" +#include "strbuf.h" + +#define SOCKET_FILE VAR_RUN"/abrt.socket" +#define SOCKET_PERMISSION 0666 + +/* Maximal length of backtrace. */ +#define MAX_BACKTRACE_SIZE (1024*1024) + +/* Amount of data received from one client for a message before reporting error. */ +#define MAX_MESSAGE_SIZE (4*MAX_BACKTRACE_SIZE) + +/* Maximum number of simultaneously opened client connections. */ +#define MAX_CLIENT_COUNT 10 + +/* Interval between checks of client halt, in seconds. */ +#define CLIENT_CHECK_INTERVAL 10 + +/* Interval with no data received from client, after which the client is + considered halted, in seconds. */ +#define CLIENT_HALT_INTERVAL 10 + +/* Maximal number of characters read from socket at once. */ +#define INPUT_BUFFER_SIZE 1024 + +static GIOChannel *channel = NULL; +static guint channel_cb_id = 0; +static int client_count = 0; + +/* Information about single socket session. */ +struct client +{ + /* Client user id */ + uid_t uid; + /* Buffer for incomplete incoming messages. */ + GByteArray *messagebuf; + /* Executable. */ + char *executable; + /* Process ID. */ + int pid; + char *backtrace; + /* Python, Ruby etc. */ + char *analyzer; + /* Directory base name: python (or pyhook), ruby etc. */ + char *basename; + /* Crash reason. + * Python example: "CCMainWindow.py:1:<module>:ZeroDivisionError: + * integer division or modulo by zero" + */ + char *reason; + /* Last time some data were received over the socket + * from the client. + */ + time_t lastwrite; + /* Timer checking client halt. */ + guint timer_id; + /* Client socket callback id. */ + guint socket_id; + /* Client socket channel */ + GIOChannel *channel; +}; + +static gboolean server_socket_cb(GIOChannel *source, + GIOCondition condition, + gpointer data); + +/* Releases all memory that belongs to a client session. */ +static void client_free(struct client *client) +{ + /* Delete the uncompleted message if there is some. */ + g_byte_array_free(client->messagebuf, TRUE); + free(client->executable); + free(client->backtrace); + free(client->analyzer); + free(client->basename); + free(client->reason); + g_source_remove(client->timer_id); + g_source_remove(client->socket_id); + g_io_channel_unref(client->channel); + free(client); + --client_count; + if (!channel_cb_id) + { + channel_cb_id = g_io_add_watch(channel, + (GIOCondition)(G_IO_IN | G_IO_PRI), + (GIOFunc)server_socket_cb, + NULL); + if (!channel_cb_id) + perror_msg_and_die("dumpsocket: Can't add socket watch"); + } +} + +/* Callback called by glib main loop at regular intervals when + some client is connected. */ +static gboolean client_check_cb(gpointer data) +{ + struct client *client = (struct client*)data; + if (time(NULL) - client->lastwrite > CLIENT_HALT_INTERVAL) + { + log("dumpsocket: client socket timeout reached, closing connection"); + client_free(client); + return FALSE; + } + return TRUE; +} + +/* Caller is responsible to free() the returned value. */ +static char *giocondition_to_string(GIOCondition condition) +{ + struct strbuf *strbuf = strbuf_new(); + if (condition & G_IO_HUP) + strbuf_append_str(strbuf, "G_IO_HUP | "); + if (condition & G_IO_ERR) + strbuf_append_str(strbuf, "G_IO_ERR | "); + if (condition & G_IO_NVAL) + strbuf_append_str(strbuf, "G_IO_NVAL | "); + if (condition & G_IO_IN) + strbuf_append_str(strbuf, "G_IO_IN | "); + if (condition & G_IO_OUT) + strbuf_append_str(strbuf, "G_IO_OUT | "); + if (condition & G_IO_PRI) + strbuf_append_str(strbuf, "G_IO_PRI | "); + if (strbuf->len == 0) + strbuf_append_str(strbuf, "none"); + else + { + /* remove the last " | " */ + strbuf->len -= 3; + strbuf->buf[strbuf->len] = '\0'; + } + char *result = strbuf->buf; + strbuf_free_nobuf(strbuf); + return result; +} + +/* Create a new debug dump from client session. + * Caller must ensure that all fields in struct client + * are properly filled. + */ +static void create_debug_dump(struct client *client) +{ + /* Create temp directory with the debug dump. + This directory is renamed to final directory name after + all files have been stored into it. + */ + char *path = xasprintf(DEBUG_DUMPS_DIR"/%s-%ld-%u.new", + client->basename, + (long)time(NULL), + client->pid); + /* No need to check the path length, as all variables used are limited, and dd.Create() + fails if the path is too long. */ + + CDebugDump dd; + try { + dd.Create(path, client->uid); + } catch (CABRTException &e) { + dd.Delete(); + dd.Close(); + error_msg_and_die("dumpsocket: Error while creating crash dump %s: %s", path, e.what()); + } + + dd.SaveText(FILENAME_ANALYZER, client->analyzer); + dd.SaveText(FILENAME_EXECUTABLE, client->executable); + dd.SaveText(FILENAME_BACKTRACE, client->backtrace); + dd.SaveText(FILENAME_REASON, client->reason); + + /* Obtain and save the command line. */ + char *cmdline = get_cmdline(client->pid); // never NULL + dd.SaveText(FILENAME_CMDLINE, cmdline); + free(cmdline); + + /* Store id of the user whose application crashed. */ + char uid_str[sizeof(long) * 3 + 2]; + sprintf(uid_str, "%lu", (long)client->uid); + dd.SaveText(CD_UID, uid_str); + + dd.Close(); + + /* Move the completely created debug dump to + final directory. */ + char *newpath = xstrndup(path, strlen(path) - strlen(".new")); + if (rename(path, newpath) == 0) + strcpy(path, newpath); + free(newpath); + + log("dumpsocket: Saved %s crash dump of pid %u to %s", + client->analyzer, client->pid, path); + + /* Handle free space checking. */ + unsigned maxCrashReportsSize = 0; + parse_conf(NULL, &maxCrashReportsSize, NULL, NULL); + if (maxCrashReportsSize > 0) + { + check_free_space(maxCrashReportsSize); + trim_debug_dumps(maxCrashReportsSize, path); + } + + free(path); +} + +/* Checks if a string contains only printable characters. */ +static bool printable_str(const char *str) +{ + do { + if ((unsigned char)(*str) < ' ' || *str == 0x7f) + return false; + str++; + } while (*str); + return true; +} + +/* Checks if a string has certain prefix. */ +static bool starts_with(const char *str, const char *start) +{ + return strncmp(str, start, strlen(start)) == 0; +} + +/* @returns + * Caller is responsible to call free() on the returned + * pointer. + * If NULL is returned, string extraction failed. + */ +static char *try_to_get_string(const char *message, + const char *tag, + size_t max_len, + bool printable, + bool allow_slashes) +{ + if (!starts_with(message, tag)) + return NULL; + + const char *contents = message + strlen(tag); + if ((printable && !printable_str(contents)) || + (!allow_slashes && strchr(contents, '/'))) + { + error_msg("dumpsocket: Received %s contains invalid characters -> skipping", tag); + return NULL; + } + + if (strlen(contents) > max_len) + { + char *max_len_str = g_format_size_for_display(max_len); + error_msg("dumpsocket: Received %s too long -> trimming to %s", tag, max_len_str); + g_free(max_len_str); + } + + return xstrndup(contents, max_len); +} + +/* Handles a message received from client over socket. */ +static void process_message(struct client *client, const char *message) +{ +/* @param tag + * The message identifier. Message starting with it + * is handled by this macro. + * @param field + * Member in struct client, which should be filled by + * the field contents. + * @param max_len + * Maximum length of the field in bytes. + * Exceeding bytes are trimmed. + * @param printable + * Whether to limit the field contents to ASCII only. + * @param allow_slashes + * Whether to allow slashes to be a part of input. + */ +#define HANDLE_INCOMING_STRING(tag, field, max_len, printable, allow_slashes) \ + char *field = try_to_get_string(message, tag, max_len, printable, allow_slashes); \ + if (field) \ + { \ + free(client->field); \ + client->field = field; \ + return; \ + } + + HANDLE_INCOMING_STRING("EXECUTABLE=", executable, PATH_MAX, true, true); + HANDLE_INCOMING_STRING("BACKTRACE=", backtrace, MAX_BACKTRACE_SIZE, false, true); + HANDLE_INCOMING_STRING("BASENAME=", basename, 100, true, false); + HANDLE_INCOMING_STRING("ANALYZER=", analyzer, 100, true, true); + HANDLE_INCOMING_STRING("REASON=", reason, 512, false, true); + +#undef HANDLE_INCOMING_STRING + + /* PID is not handled as a string, we convert it to pid_t. */ + if (starts_with(message, "PID=")) + { + /* xatou() cannot be used here, because it would + * kill whole daemon by non-numeric string. + */ + char *endptr; + errno = 0; + const char *nptr = message + strlen("PID="); + unsigned long number = strtoul(nptr, &endptr, 10); + /* pid == 0 is error, the lowest PID is 1. */ + if (errno || nptr == endptr || *endptr != '\0' || number > UINT_MAX || number == 0) + { + error_msg("dumpsocket: invalid PID received -> ignoring"); + return; + } + client->pid = number; + return; + } + + /* Creates debug dump if all fields were already provided. */ + if (starts_with(message, "DONE")) + { + if (client->pid == 0 || + client->backtrace == NULL || + client->executable == NULL || + client->analyzer == NULL || + client->basename == NULL || + client->reason == NULL) + { + error_msg("dumpsocket: DONE received, but some data are missing -> ignoring"); + return; + } + + create_debug_dump(client); + return; + } +} + +/* Callback called by glib main loop when ABRT receives data that have + * been written to the socket by some client. + */ +static gboolean client_socket_cb(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + struct client *client = (struct client*)data; + + /* Detailed logging, useful for debugging. */ + if (g_verbose >= 3) + { + char *cond = giocondition_to_string(condition); + log("dumpsocket: client condition %s", cond); + free(cond); + } + + /* Handle incoming data. */ + if (condition & (G_IO_IN | G_IO_PRI)) + { + guint loop = client->messagebuf->len; + gsize len; + gchar buf[INPUT_BUFFER_SIZE]; + GError *err = NULL; + /* Read data in chunks of size INPUT_BUFFER_SIZE. This allows to limit the number of + bytes received (to prevent memory exhaustion). */ + do { + GIOStatus result = g_io_channel_read_chars(source, buf, INPUT_BUFFER_SIZE, &len, &err); + if (result == G_IO_STATUS_ERROR) + { + g_assert(err); + error_msg("dumpsocket: Error while reading data from client socket: %s", err->message); + g_error_free(err); + client_free(client); + return FALSE; + } + + if (g_verbose >= 3) + log("dumpsocket: received %zu bytes of data", len); + + /* Append the incoming data to the message buffer. */ + g_byte_array_append(client->messagebuf, (guint8*)buf, len); + + if (client->messagebuf->len > MAX_MESSAGE_SIZE) + { + error_msg("dumpsocket: Message too long."); + client_free(client); + return FALSE; + } + } while (len > 0); + + /* Check, if we received a complete message now. */ + for (; loop < client->messagebuf->len; ++loop) + { + if (client->messagebuf->data[loop] != '\0') + continue; + + VERB3 log("dumpsocket: Processing message: %s", + client->messagebuf->data); + + /* Process the message. */ + process_message(client, (char*)client->messagebuf->data); + /* Remove the message including the ending \0 */ + g_byte_array_remove_range(client->messagebuf, 0, loop + 1); + loop = 0; + } + + /* Update the last write access time */ + client->lastwrite = time(NULL); + } + + /* Handle socket disconnection. + It is important to do it after handling G_IO_IN, because sometimes + G_IO_HUP comes together with G_IO_IN. It means that some data arrived + and then the socket has been closed. + */ + if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) + { + log("dumpsocket: Socket client disconnected"); + client_free(client); + return FALSE; + } + + return TRUE; +} + +/* If the status indicates failure, report it. */ +static void check_status(GIOStatus status, GError *err, const char *operation) +{ + if (status == G_IO_STATUS_NORMAL) + return; + + if (err) + { + error_msg("dumpsocket: Error while %s: %s", operation, err->message); + g_error_free(err); + } + else + error_msg("dumpsocket: Error while %s", operation); +} + +/* Initializes a new client session data structure. */ +static struct client *client_new(int socket) +{ + struct client *client = (struct client*)xzalloc(sizeof(struct client)); + + /* Get credentials for the socket client. */ + struct ucred cr; + socklen_t crlen = sizeof(struct ucred); + if (0 != getsockopt(socket, SOL_SOCKET, SO_PEERCRED, &cr, &crlen)) + perror_msg_and_die("dumpsocket: Failed to get client uid"); + if (crlen != sizeof(struct ucred)) + perror_msg_and_die("dumpsocket: Failed to get client uid (crlen)"); + client->uid = cr.uid; + + client->messagebuf = g_byte_array_new(); + client->lastwrite = time(NULL); + + close_on_exec_on(socket); + + /* Create client IO channel. */ + client->channel = g_io_channel_unix_new(socket); + g_io_channel_set_close_on_unref(client->channel, TRUE); + + /* Set nonblocking access. */ + GError *err = NULL; + GIOStatus status = g_io_channel_set_flags(client->channel, G_IO_FLAG_NONBLOCK, &err); + check_status(status, err, "setting NONBLOCK flag"); + + /* Disable channel encoding to protect binary data. */ + err = NULL; + status = g_io_channel_set_encoding(client->channel, NULL, &err); + check_status(status, err, "setting encoding"); + + /* Start timer to check the client problems. */ + client->timer_id = g_timeout_add_seconds(CLIENT_CHECK_INTERVAL, client_check_cb, client); + if (!client->timer_id) + error_msg_and_die("dumpsocket: Can't add client timer"); + + /* Register client callback. */ + client->socket_id = g_io_add_watch(client->channel, + (GIOCondition)(G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL), + (GIOFunc)client_socket_cb, + client); + if (!client->socket_id) + error_msg_and_die("dumpsocket: Can't add client socket watch"); + + ++client_count; + return client; +} + +/* Callback called by glib main loop when a client newly opens ABRT's socket. */ +static gboolean server_socket_cb(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ + /* Check the limit for number of simultaneously attached clients. */ + if (client_count >= MAX_CLIENT_COUNT) + { + error_msg("dumpsocket: Too many clients, refusing connection."); + /* To avoid infinite loop caused by the descriptor in "ready" state, + the callback must be disabled. + It is added back in client_free(). */ + g_source_remove(channel_cb_id); + channel_cb_id = 0; + return TRUE; + } + + struct sockaddr_un remote; + socklen_t len = sizeof(remote); + int socket = accept(g_io_channel_unix_get_fd(source), + (struct sockaddr*)&remote, &len); + if (socket == -1) + { + perror_msg("dumpsocket: Server can not accept client"); + return TRUE; + } + + log("dumpsocket: New client connected"); + client_new(socket); + return TRUE; +} + +/* Initializes the dump socket, usually in /var/run directory + * (the path depends on compile-time configuration). + */ +void dumpsocket_init() +{ + struct sockaddr_un local; + unlink(SOCKET_FILE); /* not caring about the result */ + int socketfd = xsocket(AF_UNIX, SOCK_STREAM, 0); + close_on_exec_on(socketfd); + memset(&local, 0, sizeof(local)); + local.sun_family = AF_UNIX; + strcpy(local.sun_path, SOCKET_FILE); + xbind(socketfd, (struct sockaddr*)&local, sizeof(local)); + xlisten(socketfd, MAX_CLIENT_COUNT); + + if (chmod(SOCKET_FILE, SOCKET_PERMISSION) != 0) + perror_msg_and_die("dumpsocket: failed to chmod socket file"); + + channel = g_io_channel_unix_new(socketfd); + g_io_channel_set_close_on_unref(channel, TRUE); + channel_cb_id = g_io_add_watch(channel, + (GIOCondition)(G_IO_IN | G_IO_PRI), + (GIOFunc)server_socket_cb, + NULL); + if (!channel_cb_id) + perror_msg_and_die("dumpsocket: Can't add socket watch"); +} + +/* Releases all resources used by dumpsocket. */ +void dumpsocket_shutdown() +{ + /* Set everything to pre-initialization state. */ + if (channel) + { + /* This one is for g_io_add_watch. */ + if (channel_cb_id) + g_source_remove(channel_cb_id); + /* This one is for g_io_channel_unix_new. */ + g_io_channel_unref(channel); + channel = NULL; + } +} diff --git a/src/Daemon/dumpsocket.h b/src/Daemon/dumpsocket.h new file mode 100644 index 00000000..e5b79d60 --- /dev/null +++ b/src/Daemon/dumpsocket.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2010 ABRT team + + 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. +*/ +#ifndef ABRT_DUMPSOCKET_H +#define ABRT_DUMPSOCKET_H + +/* +Unix socket in ABRT daemon for creating new dump directories. + +Why to use socket for creating dump dirs? Security. When a Python +script throwns unexpected exception, ABRT handler catches it, running +as a part of that broken Python application. The application is running +with certain SELinux privileges, for example it can not execute other +programs, or to create files in /var/cache or anything else required +to properly fill a dump directory. Adding these privileges to every +application would weaken the security. +The most suitable solution is for the Python application +to open a socket where ABRT daemon is listening, write all relevant +data to that socket, and close it. ABRT daemon handles the rest. + +** Protocol + +Initializing new dump: +open /var/run/abrt.socket + +Providing dump data (hook writes to the socket): +-> "PID=" + number 0 - PID_MAX (/proc/sys/kernel/pid_max) + \0 +-> "EXECUTABLE=" + string (maximum length ~MAX_PATH) + \0 +-> "BACKTRACE=" + string (maximum length 1 MB) + \0 +-> "ANALYZER=" + string (maximum length 100 bytes) + \0 +-> "BASENAME=" + string (maximum length 100 bytes, no slashes) + \0 +-> "REASON=" + string (maximum length 512 bytes) + \0 + +Finalizing dump creation: +-> "DONE" + \0 +*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Initializes the dump socket, usually in /var/run directory + * (the path depends on compile-time configuration). + */ +extern void dumpsocket_init(); + +/* Releases all resources used by dumpsocket. */ +extern void dumpsocket_shutdown(); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am index 6845c72c..eec2cd11 100644 --- a/src/Hooks/Makefile.am +++ b/src/Hooks/Makefile.am @@ -1,10 +1,8 @@ -libexec_PROGRAMS = abrt-hook-ccpp abrt-hook-python +libexec_PROGRAMS = abrt-hook-ccpp bin_PROGRAMS = dumpoops # abrt-hook-ccpp -abrt_hook_ccpp_SOURCES = \ - abrt-hook-ccpp.cpp \ - hooklib.h hooklib.cpp +abrt_hook_ccpp_SOURCES = abrt-hook-ccpp.cpp abrt_hook_ccpp_CPPFLAGS = \ -I$(srcdir)/../../inc \ -I$(srcdir)/../../lib/Utils \ @@ -16,8 +14,7 @@ abrt_hook_ccpp_LDADD = \ ../../lib/Utils/libABRTUtils.la # dumpoops -dumpoops_SOURCES = \ - dumpoops.cpp +dumpoops_SOURCES = dumpoops.cpp dumpoops_CPPFLAGS = \ -I$(srcdir)/../../inc \ -I$(srcdir)/../../lib/Utils \ @@ -33,28 +30,15 @@ dumpoops_LDADD = \ ../../lib/Utils/libABRTUtils.la \ ../../lib/Utils/libABRTdUtils.la -# abrt-hook-python -abrt_hook_python_SOURCES = \ - abrt-hook-python.cpp \ - hooklib.h hooklib.cpp -abrt_hook_python_CPPFLAGS = \ - -I$(srcdir)/../../inc \ - -I$(srcdir)/../../lib/Utils \ - -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DCONF_DIR=\"$(CONF_DIR)\" \ - -DVAR_RUN=\"$(VAR_RUN)\" \ - -D_GNU_SOURCE -abrt_hook_python_LDADD = \ - ../../lib/Utils/libABRTUtils.la - python_PYTHON = abrt.pth abrt_exception_handler.py EXTRA_DIST = abrt_exception_handler.py.in $(man_MANS) CLEANFILES := $(notdir $(wildcard *~)) $(notdir $(wildcard *\#)) $(notdir $(wildcard \.\#*)) $(notdir $(wildcard *.pyc)) +# Must be synchronized with another sed call below. abrt_exception_handler.py: - sed s,@DEBUG_DUMP_DIR@,$(DEBUG_DUMPS_DIR),g abrt_exception_handler.py.in > abrt_exception_handler.py + sed s,\@VAR_RUN\@,\"$(VAR_RUN)\",g abrt_exception_handler.py.in > abrt_exception_handler.py # RPM fix: we need to regenerate abrt_exception_handler.py, because it has the default ddir install-data-local: - sed s,@DEBUG_DUMP_DIR@,$(DEBUG_DUMPS_DIR),g abrt_exception_handler.py.in > abrt_exception_handler.py + sed s,\@VAR_RUN\@,\"$(VAR_RUN)\",g abrt_exception_handler.py.in > abrt_exception_handler.py diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp deleted file mode 100644 index 5f2dc809..00000000 --- a/src/Hooks/abrt-hook-python.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - abrt-hook-python.cpp - writes data to the /var/spool/abrt directory - with SUID bit - - 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 <getopt.h> -#include <syslog.h> -// We can easily get rid of abrtlib (libABRTUtils.so) usage in this file, -// but DebugDump will pull it in anyway -#include "abrtlib.h" -#include "hooklib.h" -#include "DebugDump.h" -#include "CrashTypes.h" -#include "ABRTException.h" -#if HAVE_CONFIG_H -# include <config.h> -#endif - -#define MAX_BT_SIZE (1024*1024) -#define MAX_BT_SIZE_STR "1 MB" - -static char *pid; -static char *executable; - -static bool printable_str(const char *str) -{ - do { - if ((unsigned char)(*str) < ' ' || *str == 0x7f) - return false; - str++; - } while (*str); - return true; -} - -int main(int argc, char** argv) -{ - // Parse options - static const struct option longopts[] = { - // name , has_arg , flag, val - { "pid" , required_argument, NULL, 'p' }, - { "executable", required_argument, NULL, 'e' }, - { 0 }, - }; - int opt; - while ((opt = getopt_long(argc, argv, "p:e:u:l:", longopts, NULL)) != -1) - { - switch (opt) - { - case 'p': - pid = optarg; - break; - case 'e': - executable = optarg; - break; - default: - usage: - error_msg_and_die( - "Usage: abrt-hook-python [OPTIONS] <BACKTRACE\n" - "\nOptions:\n" - " -p,--pid PID PID of process that caused the crash\n" - " -p,--executable PATH absolute path to the program that crashed\n" - ); - } - } - if (!pid || !executable) - goto usage; - if (strlen(executable) > PATH_MAX || !printable_str(executable)) - goto usage; - // pid string is sanitized later by xatou() - - openlog("abrt", LOG_PID, LOG_DAEMON); - logmode = LOGMODE_SYSLOG; - - // Error if daemon is not running - if (!daemon_is_ok()) - error_msg_and_die("daemon is not running, python crash dump aborted"); - - unsigned setting_MaxCrashReportsSize = 0; - parse_conf(NULL, &setting_MaxCrashReportsSize, NULL, NULL); - if (setting_MaxCrashReportsSize > 0) - { - check_free_space(setting_MaxCrashReportsSize); - } - - // Read the backtrace from stdin - char *bt = (char*)xmalloc(MAX_BT_SIZE); - ssize_t len = full_read(STDIN_FILENO, bt, MAX_BT_SIZE-1); - if (len < 0) - { - perror_msg_and_die("read error"); - } - bt[len] = '\0'; - if (len == MAX_BT_SIZE-1) - { - error_msg("backtrace size limit exceeded, trimming to " MAX_BT_SIZE_STR); - } - - // This also checks that pid is a valid numeric string - char *cmdline = get_cmdline(xatou(pid)); // never NULL - - // Create directory with the debug dump - char path[PATH_MAX]; - unsigned path_len = snprintf(path, sizeof(path), DEBUG_DUMPS_DIR"/pyhook-%ld-%s.new", - (long)time(NULL), pid); - if (path_len >= sizeof(path)) - exit(1); - CDebugDump dd; - try { - dd.Create(path, getuid()); - } catch (CABRTException &e) { - dd.Delete(); - dd.Close(); - error_msg_and_die("error while creating crash dump %s: %s", path, e.what()); - } - - dd.SaveText(FILENAME_ANALYZER, "Python"); - dd.SaveText(FILENAME_EXECUTABLE, executable); - dd.SaveText(FILENAME_BACKTRACE, bt); - // python handler puts a short(er) crash descr in 1st line. Example: - // "CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero" - strchrnul(bt, '\n')[0] = '\0'; - dd.SaveText(FILENAME_REASON, bt); - free(bt); - dd.SaveText(FILENAME_CMDLINE, cmdline); - free(cmdline); - char uid[sizeof(long) * 3 + 2]; - sprintf(uid, "%lu", (long)getuid()); - dd.SaveText(CD_UID, uid); - - dd.Close(); - - char *newpath = xstrndup(path, path_len - (sizeof(".new")-1)); - if (rename(path, newpath) == 0) - strcpy(path, newpath); - free(newpath); - - log("saved python crash dump of pid %s to %s", pid, path); - - if (setting_MaxCrashReportsSize > 0) - { - trim_debug_dumps(setting_MaxCrashReportsSize, path); - } - - return 0; -} diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in index a4bc93d5..99817296 100644 --- a/src/Hooks/abrt_exception_handler.py.in +++ b/src/Hooks/abrt_exception_handler.py.in @@ -19,27 +19,34 @@ ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. """ -Module for a userfriendly exception handling +Module for the ABRT exception handling hook """ import sys import os import syslog import subprocess +import socket def write_dump(pid, tb): executable = "Exception raised from python shell" if sys.argv[0]: executable = os.path.abspath(sys.argv[0]) - command = ["/usr/libexec/abrt-hook-python"] - command.append("--pid=%s" % pid) - command.append("--executable=%s" % executable) - - helper = subprocess.Popen(command, stdin=subprocess.PIPE) - helper.communicate(tb) - helper.wait() - + # Open ABRT daemon's socket and write data to it. + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(@VAR_RUN@ + "/abrt.socket") + s.sendall("PID=%s\0" % pid) + s.sendall("EXECUTABLE=%s\0" % executable) + s.sendall("ANALYZER=Python\0") + s.sendall("BASENAME=pyhook\0") + # This handler puts a short(er) crash descr in 1st line of the backtrace. + # Example: + # CCMainWindow.py:1:<module>:ZeroDivisionError: integer division or modulo by zero + s.sendall("REASON=%s\0" % tb.splitlines()[0]) + s.sendall("BACKTRACE=%s\0" % tb) + s.sendall("DONE\0") + s.close() def handleMyException((etype, value, tb)): """ |