diff options
| author | Karel Klic <kklic@redhat.com> | 2011-03-01 12:08:36 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2011-03-01 12:08:36 +0100 |
| commit | 85f639b7fe277ba327e5013e5b101b4a67f14e1d (patch) | |
| tree | 7caa3999e8c987e3ddbc26f4bfbbdc73defca73f /src/daemon | |
| parent | fb52104af74bbf6eeda394880666df40b4354aba (diff) | |
| parent | 77468fcdd7cc05db52320c373a24a5490ff32f52 (diff) | |
| download | abrt-85f639b7fe277ba327e5013e5b101b4a67f14e1d.tar.gz abrt-85f639b7fe277ba327e5013e5b101b4a67f14e1d.tar.xz abrt-85f639b7fe277ba327e5013e5b101b4a67f14e1d.zip | |
merge changes from master
Diffstat (limited to 'src/daemon')
24 files changed, 736 insertions, 1543 deletions
diff --git a/src/daemon/CommLayerServer.cpp b/src/daemon/CommLayerServer.cpp deleted file mode 100644 index 5e250121..00000000 --- a/src/daemon/CommLayerServer.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - 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 "CommLayerServer.h" -#include "CrashWatcher.h" - -CCommLayerServer::CCommLayerServer() -{ - m_init_error = 0; -} - -CCommLayerServer::~CCommLayerServer() -{ -} diff --git a/src/daemon/CommLayerServerDBus.cpp b/src/daemon/CommLayerServerDBus.cpp index 28d6ee05..133feb7b 100644 --- a/src/daemon/CommLayerServerDBus.cpp +++ b/src/daemon/CommLayerServerDBus.cpp @@ -19,12 +19,9 @@ #include <dbus/dbus.h> #include "abrtlib.h" #include "abrt_dbus.h" -#include "abrt_exception.h" #include "comm_layer_inner.h" -#include "dbus_common.h" #include "MiddleWare.h" #include "Settings.h" -#include "Daemon.h" #include "CommLayerServerDBus.h" // 16kB message limit @@ -48,6 +45,11 @@ static DBusMessage* new_signal_msg(const char* member, const char* peer = NULL) } static void send_flush_and_unref(DBusMessage* msg) { + if (!g_dbus_conn) + { + /* Not logging this, it may recurse */ + return; + } if (!dbus_connection_send(g_dbus_conn, msg, NULL /* &serial */)) error_msg_and_die("Error sending DBus message"); dbus_connection_flush(g_dbus_conn); @@ -56,7 +58,7 @@ static void send_flush_and_unref(DBusMessage* msg) } /* Notify the clients (UI) about a new crash */ -void CCommLayerServerDBus::Crash(const char *package_name, +void send_dbus_sig_Crash(const char *package_name, const char *crash_id, const char *dir, const char *uid_str @@ -84,24 +86,24 @@ void CCommLayerServerDBus::Crash(const char *package_name, send_flush_and_unref(msg); } -void CCommLayerServerDBus::QuotaExceed(const char* str) +void send_dbus_sig_QuotaExceeded(const char* str) { - DBusMessage* msg = new_signal_msg("QuotaExceed"); + DBusMessage* msg = new_signal_msg("QuotaExceeded"); dbus_message_append_args(msg, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID); - VERB2 log("Sending signal QuotaExceed('%s')", str); + VERB2 log("Sending signal QuotaExceeded('%s')", str); send_flush_and_unref(msg); } -void CCommLayerServerDBus::JobDone(const char* peer) +void send_dbus_sig_JobDone(const char* peer) { DBusMessage* msg = new_signal_msg("JobDone", peer); VERB2 log("Sending signal JobDone() to peer %s", peer); send_flush_and_unref(msg); } -void CCommLayerServerDBus::Update(const char* pMessage, const char* peer) +void send_dbus_sig_Update(const char* pMessage, const char* peer) { DBusMessage* msg = new_signal_msg("Update", peer); dbus_message_append_args(msg, @@ -110,7 +112,7 @@ void CCommLayerServerDBus::Update(const char* pMessage, const char* peer) send_flush_and_unref(msg); } -void CCommLayerServerDBus::Warning(const char* pMessage, const char* peer) +void send_dbus_sig_Warning(const char* pMessage, const char* peer) { DBusMessage* msg = new_signal_msg("Warning", peer); dbus_message_append_args(msg, @@ -144,11 +146,12 @@ static long get_remote_uid(DBusMessage* call, const char** ppSender = NULL) static int handle_GetCrashInfos(DBusMessage* call, DBusMessage* reply) { long unix_uid = get_remote_uid(call); - vector_map_crash_data_t argout1 = GetCrashInfos(unix_uid); + vector_of_crash_data_t *argout1 = GetCrashInfos(unix_uid); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); - store_val(&out_iter, argout1); + store_vector_of_crash_data(&out_iter, argout1); + free_vector_of_crash_data(argout1); send_flush_and_unref(reply); return 0; @@ -197,12 +200,12 @@ static int handle_CreateReport(DBusMessage* call, DBusMessage* reply) } long unix_uid = get_remote_uid(call); - map_crash_data_t report; - CreateReport(crash_id, unix_uid, /*force:*/ 0, report); + crash_data_t *report = NULL; + CreateReport(crash_id, unix_uid, /*force:*/ 0, &report); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); - store_val(&out_iter, report); + store_crash_data(&out_iter, report); send_flush_and_unref(reply); return 0; @@ -211,19 +214,28 @@ static int handle_CreateReport(DBusMessage* call, DBusMessage* reply) static int handle_Report(DBusMessage* call, DBusMessage* reply) { int r; + long unix_uid; + report_status_t argout1; + map_map_string_t user_conf_data; + vector_string_t events; + const char* comment = NULL; + const char* reproduce = NULL; + const char* errmsg = NULL; DBusMessageIter in_iter; + dbus_message_iter_init(call, &in_iter); - map_crash_data_t argin1; - r = load_val(&in_iter, argin1); + crash_data_t *crash_data = NULL; + r = load_crash_data(&in_iter, &crash_data); if (r != ABRT_DBUS_MORE_FIELDS) { error_msg("dbus call %s: parameter type mismatch", __func__ + 7); - return -1; + r = -1; + goto ret; } - const char* comment = get_crash_data_item_content_or_NULL(argin1, FILENAME_COMMENT) ? : ""; - const char* reproduce = get_crash_data_item_content_or_NULL(argin1, FILENAME_REPRODUCE) ? : ""; - const char* errmsg = NULL; +//TODO? get_crash_item_content_or_die_or_empty? + comment = get_crash_item_content_or_NULL(crash_data, FILENAME_COMMENT) ? : ""; + reproduce = get_crash_item_content_or_NULL(crash_data, FILENAME_REPRODUCE) ? : ""; if (strlen(comment) > LIMIT_MESSAGE) { errmsg = _("Comment is too long"); @@ -239,52 +251,43 @@ static int handle_Report(DBusMessage* call, DBusMessage* reply) if (!reply) die_out_of_memory(); send_flush_and_unref(reply); - return 0; + r = 0; + goto ret; } /* Second parameter: list of events to run */ - vector_string_t events; r = load_val(&in_iter, events); if (r == ABRT_DBUS_ERROR) { error_msg("dbus call %s: parameter type mismatch", __func__ + 7); - return -1; + r = -1; + goto ret; } /* Third parameter (optional): configuration data for plugins */ - map_map_string_t user_conf_data; if (r == ABRT_DBUS_MORE_FIELDS) { r = load_val(&in_iter, user_conf_data); if (r != ABRT_DBUS_LAST_FIELD) { error_msg("dbus call %s: parameter type mismatch", __func__ + 7); - return -1; + r = -1; + goto ret; } } - long unix_uid = get_remote_uid(call); - report_status_t argout1; - try - { - argout1 = Report(argin1, events, user_conf_data, unix_uid); - } - catch (CABRTException &e) - { - dbus_message_unref(reply); - reply = dbus_message_new_error(call, DBUS_ERROR_FAILED, e.what()); - if (!reply) - die_out_of_memory(); - send_flush_and_unref(reply); - return 0; - } + unix_uid = get_remote_uid(call); + argout1 = Report(crash_data, events, user_conf_data, unix_uid); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); store_val(&out_iter, argout1); send_flush_and_unref(reply); - return 0; + r = 0; + ret: + free_crash_data(crash_data); + return r; } static int handle_DeleteDebugDump(DBusMessage* call, DBusMessage* reply) @@ -339,12 +342,13 @@ static int handle_GetPluginSettings(DBusMessage* call, DBusMessage* reply) //long unix_uid = get_remote_uid(call); //VERB1 log("got %s('%s') call from uid %ld", "GetPluginSettings", PluginName, unix_uid); - map_plugin_settings_t plugin_settings; - GetPluginSettings(PluginName, plugin_settings); + map_string_h *plugin_settings = GetPluginSettings(PluginName); DBusMessageIter out_iter; dbus_message_iter_init_append(reply, &out_iter); - store_val(&out_iter, plugin_settings); + store_map_string(&out_iter, plugin_settings); + + free_map_string(plugin_settings); send_flush_and_unref(reply); return 0; @@ -362,25 +366,25 @@ static int handle_GetSettings(DBusMessage* call, DBusMessage* reply) return 0; } -static int handle_SetSettings(DBusMessage* call, DBusMessage* reply) -{ - int r; - DBusMessageIter in_iter; - dbus_message_iter_init(call, &in_iter); - map_abrt_settings_t param1; - r = load_val(&in_iter, param1); - if (r != ABRT_DBUS_LAST_FIELD) - { - error_msg("dbus call %s: parameter type mismatch", __func__ + 7); - return -1; - } - - const char * sender = dbus_message_get_sender(call); - SetSettings(param1, sender); - - send_flush_and_unref(reply); - return 0; -} +//static int handle_SetSettings(DBusMessage* call, DBusMessage* reply) +//{ +// int r; +// DBusMessageIter in_iter; +// dbus_message_iter_init(call, &in_iter); +// map_abrt_settings_t param1; +// r = load_val(&in_iter, param1); +// if (r != ABRT_DBUS_LAST_FIELD) +// { +// error_msg("dbus call %s: parameter type mismatch", __func__ + 7); +// return -1; +// } +// +// const char * sender = dbus_message_get_sender(call); +// SetSettings(param1, sender); +// +// send_flush_and_unref(reply); +// return 0; +//} /* @@ -413,8 +417,11 @@ static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg r = handle_GetPluginSettings(msg, reply); else if (strcmp(member, "GetSettings") == 0) r = handle_GetSettings(msg, reply); - else if (strcmp(member, "SetSettings") == 0) - r = handle_SetSettings(msg, reply); +// looks unused to me. +// Ok to grep for SetSettings and delete after 2011-04-01. +// else if (strcmp(member, "SetSettings") == 0) +// r = handle_SetSettings(msg, reply); + // NB: C++ binding also handles "Introspect" method, which returns a string. // It was sending "dummy" introspection answer whick looks like this: // "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n" @@ -460,7 +467,7 @@ static void handle_dbus_err(bool error_flag, DBusError *err) ABRTD_DBUS_NAME); } -CCommLayerServerDBus::CCommLayerServerDBus() +int init_dbus() { DBusConnection* conn; DBusError err; @@ -481,7 +488,7 @@ CCommLayerServerDBus::CCommLayerServerDBus() // // dbus-daemon drops connections if it recvs a malformed message // (we actually observed this when we sent bad UTF-8 string). - // Currently, in this case abrtd just exits with exitcode 1. + // Currently, in this case abrtd just exits with exit code 1. // (symptom: last two log messages are "abrtd: remove_watch()") // If we want to have better logging or other nontrivial handling, // here we need to do: @@ -510,9 +517,15 @@ CCommLayerServerDBus::CCommLayerServerDBus() int cnt = 10; while (dbus_connection_dispatch(conn) != DBUS_DISPATCH_COMPLETE && --cnt) VERB3 log("processed initial buffered dbus message"); + + return 0; } -CCommLayerServerDBus::~CCommLayerServerDBus() +void deinit_dbus() { - dbus_connection_unref(g_dbus_conn); + if (g_dbus_conn != NULL) + { + dbus_connection_unref(g_dbus_conn); + g_dbus_conn = NULL; + } } diff --git a/src/daemon/CommLayerServerDBus.h b/src/daemon/CommLayerServerDBus.h index df767436..979fef69 100644 --- a/src/daemon/CommLayerServerDBus.h +++ b/src/daemon/CommLayerServerDBus.h @@ -19,26 +19,26 @@ #ifndef COMMLAYERSERVERDBUS_H_ #define COMMLAYERSERVERDBUS_H_ -#include "CommLayerServer.h" +#ifdef __cplusplus +extern "C" { +#endif -class CCommLayerServerDBus -: public CCommLayerServer -{ - public: - CCommLayerServerDBus(); - virtual ~CCommLayerServerDBus(); +int init_dbus(void); +void deinit_dbus(void); - /* DBus signal senders */ - virtual void Crash(const char *package_name, +void send_dbus_sig_Crash(const char *package_name, const char *crash_id, const char *dir, const char *uid_str - ); - virtual void JobDone(const char* peer); - virtual void QuotaExceed(const char* str); +); +void send_dbus_sig_JobDone(const char* peer); +void send_dbus_sig_QuotaExceeded(const char* str); + +void send_dbus_sig_Update(const char* pMessage, const char* peer); +void send_dbus_sig_Warning(const char* pMessage, const char* peer); - virtual void Update(const char* pMessage, const char* peer); - virtual void Warning(const char* pMessage, const char* peer); -}; +#ifdef __cplusplus +} +#endif #endif diff --git a/src/daemon/CrashWatcher.cpp b/src/daemon/CrashWatcher.cpp deleted file mode 100644 index a74fa3aa..00000000 --- a/src/daemon/CrashWatcher.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com) - 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 "abrtlib.h" -#include "Daemon.h" -#include "CommLayerServer.h" -#include "CrashWatcher.h" - -void CCrashWatcher::Status(const char *pMessage, const char* peer) -{ - VERB1 log("Update('%s'): %s", peer, pMessage); - if (g_pCommLayer != NULL) - g_pCommLayer->Update(pMessage, peer); -} - -void CCrashWatcher::Warning(const char *pMessage, const char* peer) -{ - VERB1 log("Warning('%s'): %s", peer, pMessage); - if (g_pCommLayer != NULL) - g_pCommLayer->Warning(pMessage, peer); -} - -CCrashWatcher::CCrashWatcher() -{ -} - -CCrashWatcher::~CCrashWatcher() -{ -} diff --git a/src/daemon/CrashWatcher.h b/src/daemon/CrashWatcher.h deleted file mode 100644 index 4f755a36..00000000 --- a/src/daemon/CrashWatcher.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - Copyright (C) 2009 Jiri Moskovcak (jmoskovc@redhat.com) - 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. -*/ -#ifndef CRASHWATCHER_H_ -#define CRASHWATCHER_H_ - -#include "observer.h" - - -class CCrashWatcher -: public CObserver -{ - public: - CCrashWatcher(); - virtual ~CCrashWatcher(); - - public: - /* Observer methods */ - virtual void Status(const char *pMessage, const char* peer); - virtual void Warning(const char *pMessage, const char* peer); -}; - -#endif diff --git a/src/daemon/Daemon.cpp b/src/daemon/Daemon.cpp index 609b0b26..f791fb38 100644 --- a/src/daemon/Daemon.cpp +++ b/src/daemon/Daemon.cpp @@ -25,21 +25,18 @@ #include <string> #include <sys/inotify.h> #include <sys/ioctl.h> /* ioctl(FIONREAD) */ -#include <glib.h> #include "abrtlib.h" -#include "abrt_exception.h" #include "comm_layer_inner.h" #include "Settings.h" #include "CommLayerServerDBus.h" -#include "CrashWatcher.h" #include "MiddleWare.h" -#include "Daemon.h" #include "parse_options.h" +#define PROGNAME "abrtd" + using namespace std; -#define VAR_RUN_LOCK_FILE VAR_RUN"/abrt/abrtd.lock" #define VAR_RUN_PIDFILE VAR_RUN"/abrtd.pid" #define SOCKET_FILE VAR_RUN"/abrt/abrt.socket" @@ -55,15 +52,15 @@ using namespace std; * - signal: we got SIGTERM or SIGINT * * DBus methods we have: - * - GetCrashInfos(): returns a vector_map_crash_data_t (vector_map_vector_string_t) + * - GetCrashInfos(): returns a vector_of_crash_data * of crashes for given uid * v[N]["executable"/"uid"/"kernel"/"backtrace"][N] = "contents" * - StartJob(crash_id,force): starts creating a report for /var/spool/abrt/DIR with this UID:UUID. * Returns job id (uint64). * After thread returns, when report creation thread has finished, * JobDone() dbus signal is emitted. - * - CreateReport(crash_id): returns map_crash_data_t (map_vector_string_t) - * - Report(map_crash_data_t (map_vector_string_t[, map_map_string_t])): + * - CreateReport(crash_id): returns crash data (hash table of struct crash_item) + * - Report(crash_data[, map_map_string_t]): * "Please report this crash": calls Report() of all registered reporter plugins. * Returns report_status_t (map_vector_string_t) - the status of each call. * 2nd parameter is the contents of user's abrt.conf. @@ -85,12 +82,11 @@ using namespace std; * Both are sent as unicast to last client set by set_client_name(name). * If set_client_name(NULL) was done, they are not sent. */ -CCommLayerServer* g_pCommLayer; - static volatile sig_atomic_t s_sig_caught; static int s_signal_pipe[2]; static int s_signal_pipe_write = -1; static int s_upload_watch = -1; +static pid_t log_scanner_pid = -1; static unsigned s_timeout; static bool s_exiting; @@ -203,205 +199,36 @@ static void dumpsocket_shutdown() } } - -/* Cron handling */ - -typedef struct cron_callback_data_t -{ - std::string m_sPluginName; - std::string m_sPluginArgs; - unsigned int m_nTimeout; - - cron_callback_data_t( - const std::string& pPluginName, - const std::string& pPluginArgs, - const unsigned int& pTimeout) : - m_sPluginName(pPluginName), - m_sPluginArgs(pPluginArgs), - m_nTimeout(pTimeout) - {} -} cron_callback_data_t; - -static void cron_delete_callback_data_cb(gpointer data) -{ - cron_callback_data_t* cronDeleteCallbackData = static_cast<cron_callback_data_t*>(data); - delete cronDeleteCallbackData; -} - -static gboolean cron_activation_periodic_cb(gpointer data) +static int create_pidfile() { - cron_callback_data_t* cronPeriodicCallbackData = static_cast<cron_callback_data_t*>(data); - VERB1 log("Activating plugin: %s", cronPeriodicCallbackData->m_sPluginName.c_str()); - RunAction(DEBUG_DUMPS_DIR, - cronPeriodicCallbackData->m_sPluginName.c_str(), - cronPeriodicCallbackData->m_sPluginArgs.c_str() - ); - return TRUE; -} -static gboolean cron_activation_one_cb(gpointer data) -{ - cron_callback_data_t* cronOneCallbackData = static_cast<cron_callback_data_t*>(data); - VERB1 log("Activating plugin: %s", cronOneCallbackData->m_sPluginName.c_str()); - RunAction(DEBUG_DUMPS_DIR, - cronOneCallbackData->m_sPluginName.c_str(), - cronOneCallbackData->m_sPluginArgs.c_str() - ); - return FALSE; -} -static gboolean cron_activation_reshedule_cb(gpointer data) -{ - cron_callback_data_t* cronResheduleCallbackData = static_cast<cron_callback_data_t*>(data); - VERB1 log("Rescheduling plugin: %s", cronResheduleCallbackData->m_sPluginName.c_str()); - cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(cronResheduleCallbackData->m_sPluginName, - cronResheduleCallbackData->m_sPluginArgs, - cronResheduleCallbackData->m_nTimeout); - g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, - cronPeriodicCallbackData->m_nTimeout, - cron_activation_periodic_cb, - static_cast<gpointer>(cronPeriodicCallbackData), - cron_delete_callback_data_cb - ); - return FALSE; -} - -static int SetUpCron() -{ - map_cron_t::iterator it_c = g_settings_mapCron.begin(); - for (; it_c != g_settings_mapCron.end(); it_c++) + /* Note: + * No O_EXCL: we would happily overwrite stale pidfile from previous boot. + * No O_TRUNC: we must first try to lock the file, and if lock fails, + * there is another live abrtd. O_TRUNCing the file in this case + * would be wrong - it'll erase the pid to empty string! + */ + int fd = open(VAR_RUN_PIDFILE, O_WRONLY|O_CREAT, 0644); + if (fd >= 0) { - std::string::size_type pos = it_c->first.find(":"); - int timeout = 0; - int nH = -1; - int nM = -1; - int nS = -1; - -//TODO: rewrite using good old sscanf? - - if (pos != std::string::npos) - { - std::string sH; - std::string sM; - - sH = it_c->first.substr(0, pos); - nH = xatou(sH.c_str()); - nH = nH > 23 ? 23 : nH; - nH = nH < 0 ? 0 : nH; - timeout += nH * 60 * 60; - sM = it_c->first.substr(pos + 1); - nM = xatou(sM.c_str()); - nM = nM > 59 ? 59 : nM; - nM = nM < 0 ? 0 : nM; - timeout += nM * 60; - } - else - { - std::string sS; - - sS = it_c->first; - nS = xatou(sS.c_str()); - nS = nS <= 0 ? 1 : nS; - timeout = nS; - } - - if (nS != -1) + if (lockf(fd, F_TLOCK, 0) < 0) { - vector_pair_string_string_t::iterator it_ar = it_c->second.begin(); - for (; it_ar != it_c->second.end(); it_ar++) - { - cron_callback_data_t* cronPeriodicCallbackData = new cron_callback_data_t(it_ar->first, it_ar->second, timeout); - g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, - timeout, - cron_activation_periodic_cb, - static_cast<gpointer>(cronPeriodicCallbackData), - cron_delete_callback_data_cb); - } + perror_msg("Can't lock file '%s'", VAR_RUN_PIDFILE); + return -1; } - else - { - time_t actTime = time(NULL); - struct tm locTime; - localtime_r(&actTime, &locTime); - locTime.tm_hour = nH; - locTime.tm_min = nM; - locTime.tm_sec = 0; - time_t nextTime = mktime(&locTime); - if (nextTime == ((time_t)-1)) - { - /* paranoia */ - perror_msg("Can't set up cron time"); - return -1; - } - if (actTime > nextTime) - { - timeout = 24*60*60 + (nextTime - actTime); - } - else - { - timeout = nextTime - actTime; - } - vector_pair_string_string_t::iterator it_ar = it_c->second.begin(); - for (; it_ar != it_c->second.end(); it_ar++) - { - cron_callback_data_t* cronOneCallbackData = new cron_callback_data_t(it_ar->first, it_ar->second, timeout); - g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, - timeout, - cron_activation_one_cb, - static_cast<gpointer>(cronOneCallbackData), - cron_delete_callback_data_cb); - cron_callback_data_t* cronResheduleCallbackData = new cron_callback_data_t(it_ar->first, it_ar->second, 24 * 60 * 60); - g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, - timeout, - cron_activation_reshedule_cb, - static_cast<gpointer>(cronResheduleCallbackData), - cron_delete_callback_data_cb); - } - } - } - return 0; -} - -static int CreatePidFile() -{ - int fd; - - /* JIC */ - unlink(VAR_RUN_PIDFILE); - - /* open the pidfile */ - fd = open(VAR_RUN_PIDFILE, O_WRONLY|O_CREAT|O_EXCL, 0644); - if (fd >= 0) - { + close_on_exec_on(fd); /* write our pid to it */ char buf[sizeof(long)*3 + 2]; int len = sprintf(buf, "%lu\n", (long)getpid()); write(fd, buf, len); - close(fd); + ftruncate(fd, len); + /* we leak opened+locked fd intentionally */ return 0; } - /* something went wrong */ perror_msg("Can't open '%s'", VAR_RUN_PIDFILE); return -1; } -static int Lock() -{ - int lfd = open(VAR_RUN_LOCK_FILE, O_RDWR|O_CREAT, 0640); - if (lfd < 0) - { - perror_msg("Can't open '%s'", VAR_RUN_LOCK_FILE); - return -1; - } - if (lockf(lfd, F_TLOCK, 0) < 0) - { - perror_msg("Can't lock file '%s'", VAR_RUN_LOCK_FILE); - return -1; - } - close_on_exec_on(lfd); - return 0; - /* we leak opened lfd intentionally */ -} - static void handle_signal(int signo) { int save_errno = errno; @@ -433,12 +260,22 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint s_exiting = 1; else { - if (socket_client_count) - socket_client_count--; - if (!socket_channel_cb_id) + pid_t pid; + while ((pid = waitpid(-1, NULL, WNOHANG)) > 0) { - log("Accepting connections on '%s'", SOCKET_FILE); - socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb); + if (pid == log_scanner_pid) + { + log("log scanner exited"); + log_scanner_pid = -1; + continue; + } + if (socket_client_count) + socket_client_count--; + if (!socket_channel_cb_id) + { + log("Accepting connections on '%s'", SOCKET_FILE); + socket_channel_cb_id = add_watch_or_die(socket_channel, G_IO_IN | G_IO_PRI, server_socket_cb); + } } } return TRUE; @@ -531,76 +368,63 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin && worst_dir ) { log("Size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, g_settings_nMaxCrashReportsSize, worst_dir); - g_pCommLayer->QuotaExceed(_("The size of the report exceeded the quota. Please check system's MaxCrashReportsSize value in abrt.conf.")); + send_dbus_sig_QuotaExceeded(_("The size of the report exceeded the quota. Please check system's MaxCrashReportsSize value in abrt.conf.")); /* deletes both directory and DB record */ char *d = concat_path_file(DEBUG_DUMPS_DIR, worst_dir); free(worst_dir); worst_dir = NULL; - delete_crash_dump_dir(d); + delete_dump_dir(d); free(d); } } char *fullname = NULL; - try + crash_data_t *crash_data = NULL; + fullname = concat_path_file(DEBUG_DUMPS_DIR, name); + mw_result_t res = LoadDebugDump(fullname, &crash_data); + switch (res) { - fullname = concat_path_file(DEBUG_DUMPS_DIR, name); - map_crash_data_t crashinfo; - mw_result_t res = LoadDebugDump(fullname, crashinfo); - switch (res) - { - case MW_OK: - log("New crash %s, processing", fullname); - /* Fall through */ + case MW_OK: + log("New crash %s, processing", fullname); + /* Fall through */ - case MW_OCCURRED: /* dup */ + case MW_OCCURRED: /* dup */ + { + if (res != MW_OK) { - if (res != MW_OK) - { - const char *first = get_crash_data_item_content_or_NULL(crashinfo, CD_DUMPDIR); - log("Deleting crash %s (dup of %s), sending dbus signal", - strrchr(fullname, '/') + 1, - strrchr(first, '/') + 1); - delete_crash_dump_dir(fullname); - } - - const char *uid_str = get_crash_data_item_content_or_NULL(crashinfo, FILENAME_UID); - const char *inform_all = get_crash_data_item_content_or_NULL(crashinfo, FILENAME_INFORMALL); - - if (inform_all && string_to_bool(inform_all)) - uid_str = NULL; - char *crash_id = xasprintf("%s:%s", - get_crash_data_item_content_or_NULL(crashinfo, FILENAME_UID), - get_crash_data_item_content_or_NULL(crashinfo, FILENAME_UUID) - ); - /* Send dbus signal */ - g_pCommLayer->Crash(get_crash_data_item_content_or_NULL(crashinfo, FILENAME_PACKAGE), - crash_id, //TODO: stop passing this param, it is unused - fullname, - uid_str - ); - free(crash_id); - break; + const char *first = get_crash_item_content_or_NULL(crash_data, CD_DUMPDIR); + log("Deleting crash %s (dup of %s), sending dbus signal", + strrchr(fullname, '/') + 1, + strrchr(first, '/') + 1); + delete_dump_dir(fullname); } - case MW_CORRUPTED: - case MW_GPG_ERROR: - default: - log("Corrupted or bad crash %s (res:%d), deleting", fullname, (int)res); - delete_crash_dump_dir(fullname); - break; + + const char *uid_str = get_crash_item_content_or_NULL(crash_data, FILENAME_UID); + const char *inform_all = get_crash_item_content_or_NULL(crash_data, FILENAME_INFORMALL); + + if (inform_all && string_to_bool(inform_all)) + uid_str = NULL; + char *crash_id = xasprintf("%s:%s", + get_crash_item_content_or_NULL(crash_data, FILENAME_UID), + get_crash_item_content_or_NULL(crash_data, FILENAME_UUID) + ); + send_dbus_sig_Crash(get_crash_item_content_or_NULL(crash_data, FILENAME_PACKAGE), + crash_id, //TODO: stop passing this param, it is unused + fullname, + uid_str + ); + free(crash_id); + break; } - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - } - catch (...) - { - free(fullname); - free(buf); - throw; + case MW_CORRUPTED: + case MW_GPG_ERROR: + default: + log("Corrupted or bad crash %s (res:%d), deleting", fullname, (int)res); + delete_dump_dir(fullname); + break; } free(fullname); + free_crash_data(crash_data); } /* while */ free(buf); @@ -636,10 +460,10 @@ static void run_main_loop(GMainLoop* loop) fds = (GPollFD *)xrealloc(fds, fds_size * sizeof(fds[0])); } - if (s_timeout) + if (s_timeout != 0) alarm(s_timeout); g_poll(fds, nfds, timeout); - if (s_timeout) + if (s_timeout != 0) alarm(0); some_ready = g_main_context_check(context, max_priority, fds, nfds); @@ -659,8 +483,9 @@ static void start_syslog_logging() * Otherwise fprintf(stderr) dumps messages into random fds, etc. */ xdup2(STDIN_FILENO, STDOUT_FILENO); xdup2(STDIN_FILENO, STDERR_FILENO); - openlog("abrtd", 0, LOG_DAEMON); + openlog(PROGNAME, 0, LOG_DAEMON); logmode = LOGMODE_SYSLOG; + putenv((char*)"ABRT_SYSLOG=1"); } static void ensure_writable_dir(const char *dir, mode_t mode, const char *user) @@ -690,28 +515,11 @@ static void sanitize_dump_dir_rights() /* 00777 bits are usual "rwxrwxrwx" access rights */ ensure_writable_dir(DEBUG_DUMPS_DIR, 0755, "abrt"); /* debuginfo cache */ - ensure_writable_dir(DEBUG_INFO_DIR, 0755, "root"); + ensure_writable_dir(DEBUG_INFO_DIR, 0775, "abrt"); /* temp dir */ ensure_writable_dir(VAR_RUN"/abrt", 0755, "root"); } -static char *timeout_opt; -static const char* abrtd_usage = _("abrtd [options]"); -enum { - OPT_v = 1 << 0, - OPT_d = 1 << 1, - OPT_s = 1 << 2, - OPT_t = 1 << 3, -}; -/* Keep enum above and order of options below in sync! */ -static struct options abrtd_options[] = { - OPT__VERBOSE(&g_verbose), - OPT_BOOL( 'd' , 0, NULL, _("Do not daemonize")), - OPT_BOOL( 's' , 0, NULL, _("Log to syslog even with -d")), - OPT_INTEGER( 't' , 0, &timeout_opt, _("Exit after SEC seconds of inactivity")), - OPT_END() -}; - int main(int argc, char** argv) { int parent_pid = getpid(); @@ -730,26 +538,37 @@ int main(int argc, char** argv) if (env_verbose) g_verbose = atoi(env_verbose); - unsigned opts = parse_opts(argc, argv, abrtd_options, abrtd_usage); - - if (opts & OPT_s) - start_syslog_logging(); - + const char *program_usage_string = _( + PROGNAME" [options]" + ); + enum { + OPT_v = 1 << 0, + OPT_d = 1 << 1, + OPT_s = 1 << 2, + OPT_t = 1 << 3, + }; + /* Keep enum above and order of options below in sync! */ + struct options program_options[] = { + OPT__VERBOSE(&g_verbose), + OPT_BOOL( 'd', NULL, NULL , _("Do not daemonize")), + OPT_BOOL( 's', NULL, NULL , _("Log to syslog even with -d")), + OPT_INTEGER('t', NULL, &s_timeout, _("Exit after SEC seconds of inactivity")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); + + unsetenv("ABRT_SYSLOG"); + putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); /* When dbus daemon starts us, it doesn't set PATH * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE). * In this case, set something sane: */ - /* Need to add LIBEXEC_DIR to PATH, because otherwise abrt-action-* - * are not found by exec() - */ const char *env_path = getenv("PATH"); if (!env_path || !env_path[0]) - env_path = "/usr/sbin:/usr/bin:/sbin:/bin"; - putenv(xasprintf("PATH=%s:%s", LIBEXEC_DIR, env_path)); - - putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - - msg_prefix = "abrtd"; /* for log(), error_msg() and such */ + putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin"); + msg_prefix = PROGNAME; /* for log(), error_msg() and such */ + if (opts & OPT_s) + start_syslog_logging(); xpipe(s_signal_pipe); close_on_exec_on(s_signal_pipe[0]); @@ -757,7 +576,7 @@ int main(int argc, char** argv) signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGCHLD, handle_signal); - if (s_timeout) + if (s_timeout != 0) signal(SIGALRM, handle_signal); /* Daemonize unless -d */ @@ -799,37 +618,43 @@ int main(int argc, char** argv) guint channel_inotify_event_id = 0; GIOChannel* channel_signal = NULL; guint channel_signal_event_id = 0; - bool lockfile_created = false; bool pidfile_created = false; - CCrashWatcher watcher; /* Initialization */ try { - init_daemon_logging(&watcher); + init_daemon_logging(); VERB1 log("Loading settings"); - if (LoadSettings() != 0) + if (load_settings() != 0) throw 1; + sanitize_dump_dir_rights(); + VERB1 log("Creating glib main loop"); pMainloop = g_main_loop_new(NULL, FALSE); VERB1 log("Initializing inotify"); - sanitize_dump_dir_rights(); errno = 0; int inotify_fd = inotify_init(); if (inotify_fd == -1) perror_msg_and_die("inotify_init failed"); close_on_exec_on(inotify_fd); + /* Watching DEBUG_DUMPS_DIR for new files... */ if (inotify_add_watch(inotify_fd, DEBUG_DUMPS_DIR, IN_CREATE | IN_MOVED_TO) < 0) - perror_msg_and_die("inotify_add_watch failed on '%s'", DEBUG_DUMPS_DIR); + { + perror_msg("inotify_add_watch failed on '%s'", DEBUG_DUMPS_DIR); + throw 1; + } if (g_settings_sWatchCrashdumpArchiveDir) { s_upload_watch = inotify_add_watch(inotify_fd, g_settings_sWatchCrashdumpArchiveDir, IN_CLOSE_WRITE|IN_MOVED_TO); if (s_upload_watch < 0) - perror_msg_and_die("inotify_add_watch failed on '%s'", g_settings_sWatchCrashdumpArchiveDir); + { + perror_msg("inotify_add_watch failed on '%s'", g_settings_sWatchCrashdumpArchiveDir); + throw 1; + } } VERB1 log("Adding inotify watch to glib main loop"); channel_inotify = g_io_channel_unix_new(inotify_fd); @@ -838,13 +663,6 @@ int main(int argc, char** argv) handle_inotify_cb, NULL); - VERB1 log("Loading plugins from "PLUGINS_LIB_DIR); - g_pPluginManager = new CPluginManager(); - g_pPluginManager->LoadPlugins(); - - if (SetUpCron() != 0) - throw 1; - /* Add an event source which waits for INT/TERM signal */ VERB1 log("Adding signal pipe watch to glib main loop"); channel_signal = g_io_channel_unix_new(s_signal_pipe[0]); @@ -854,12 +672,8 @@ int main(int argc, char** argv) NULL); /* Mark the territory */ - VERB1 log("Creating lock file"); - if (Lock() != 0) - throw 1; - lockfile_created = true; VERB1 log("Creating pid file"); - if (CreatePidFile() != 0) + if (create_pidfile() != 0) throw 1; pidfile_created = true; @@ -870,8 +684,7 @@ int main(int argc, char** argv) * therefore it should be the last thing to initialize. */ VERB1 log("Initializing dbus"); - g_pCommLayer = new CCommLayerServerDBus(); - if (g_pCommLayer->m_init_error) + if (init_dbus() != 0) throw 1; } catch (...) @@ -896,21 +709,26 @@ int main(int argc, char** argv) /* Only now we want signal pipe to work */ s_signal_pipe_write = s_signal_pipe[1]; - /* Enter the event loop */ - try - { - log("Init complete, entering main loop"); - run_main_loop(pMainloop); - } - catch (CABRTException& e) + if (g_settings_sLogScanners) { - error_msg("Error: %s", e.what()); - } - catch (std::exception& e) - { - error_msg("Error: %s", e.what()); + const char *scanner_argv[] = { + "/bin/sh", "-c", + g_settings_sLogScanners, + NULL + }; + log_scanner_pid = fork_execv_on_steroids(EXECFLG_INPUT_NUL, + (char**)scanner_argv, + /*pipefds:*/ NULL, + /*unsetenv_vec:*/ NULL, + /*dir:*/ NULL, + /*uid:*/ 0); + VERB1 log("Started log scanner, pid:%d", (int)log_scanner_pid); } + /* Enter the event loop */ + log("Init complete, entering main loop"); + run_main_loop(pMainloop); + cleanup: /* Error or INT/TERM. Clean up, in reverse order. * Take care to not undo things we did not do. @@ -918,8 +736,6 @@ int main(int argc, char** argv) dumpsocket_shutdown(); if (pidfile_created) unlink(VAR_RUN_PIDFILE); - if (lockfile_created) - unlink(VAR_RUN_LOCK_FILE); if (channel_signal_event_id > 0) g_source_remove(channel_signal_event_id); @@ -930,21 +746,23 @@ int main(int argc, char** argv) if (channel_inotify) g_io_channel_unref(channel_inotify); - delete g_pCommLayer; - if (g_pPluginManager) - { - /* This restores /proc/sys/kernel/core_pattern, among other things: */ - g_pPluginManager->UnLoadPlugins(); - delete g_pPluginManager; - } + deinit_dbus(); + if (pMainloop) g_main_loop_unref(pMainloop); - settings_free(); + free_settings(); + + if (log_scanner_pid > 0) + { + VERB2 log("Sending SIGTERM to %d", log_scanner_pid); + kill(log_scanner_pid, SIGTERM); + } + /* Exiting */ if (s_sig_caught && s_sig_caught != SIGALRM && s_sig_caught != SIGCHLD) { - error_msg_and_die("Got signal %d, exiting", s_sig_caught); + error_msg("Got signal %d, exiting", s_sig_caught); signal(s_sig_caught, SIG_DFL); raise(s_sig_caught); } diff --git a/src/daemon/Daemon.h b/src/daemon/Daemon.h deleted file mode 100644 index 158b48fb..00000000 --- a/src/daemon/Daemon.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright (C) 2009 Denys Vlasenko (dvlasenk@redhat.com) - 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. -*/ -#ifndef DAEMON_H_ -#define DAEMON_H_ - -#include <pthread.h> -#include "abrt_types.h" -#include "abrt_crash_dump.h" - -class CCrashWatcher; -class CCommLayerServer; -class CPluginManager; - -/* Used for sending dbus signals */ -extern CCommLayerServer *g_pCommLayer; - -/* Collection of loaded plugins */ -extern CPluginManager* g_pPluginManager; - -#endif diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am index 34c7aa7b..6fe73065 100644 --- a/src/daemon/Makefile.am +++ b/src/daemon/Makefile.am @@ -1,24 +1,22 @@ bin_SCRIPTS = \ abrt-handle-upload -libexec_PROGRAMS = \ - abrt-action-save-package-data bin_PROGRAMS = \ - abrt-handle-crashdump + abrt-handle-crashdump \ + abrt-action-save-package-data -sbin_PROGRAMS = abrtd \ +sbin_PROGRAMS = \ + abrtd \ abrt-server abrtd_SOURCES = \ - PluginManager.h PluginManager.cpp \ MiddleWare.h MiddleWare.cpp \ - CrashWatcher.h CrashWatcher.cpp \ - CommLayerServer.h CommLayerServer.cpp \ CommLayerServerDBus.h CommLayerServerDBus.cpp \ Settings.h Settings.cpp \ - Daemon.h Daemon.cpp + comm_layer_inner.h comm_layer_inner.cpp \ + Daemon.cpp abrtd_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -36,14 +34,13 @@ abrtd_CPPFLAGS = \ abrtd_LDADD = \ $(DL_LIBS) \ $(DBUS_LIBS) \ - ../lib/libabrt.la \ - ../lib/libabrt_daemon.la \ + ../lib/libreport.la \ ../lib/libabrt_dbus.la abrt_server_SOURCES = \ abrt-server.c abrt_server_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -52,15 +49,16 @@ abrt_server_CPPFLAGS = \ -DDEBUG_INFO_DIR=\"$(DEBUG_INFO_DIR)\" \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_server_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_handle_crashdump_SOURCES = \ abrt-handle-crashdump.c abrt_handle_crashdump_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -71,17 +69,18 @@ abrt_handle_crashdump_CPPFLAGS = \ -DPLUGINS_LIB_DIR=\"$(PLUGINS_LIB_DIR)\" \ -DPLUGINS_CONF_DIR=\"$(PLUGINS_CONF_DIR)\" \ -DLIBEXEC_DIR=\"$(LIBEXEC_DIR)\" \ + $(GLIB_CFLAGS) \ -D_GNU_SOURCE \ -Wall -Werror abrt_handle_crashdump_LDADD = \ - ../lib/libabrt.la + ../lib/libreport.la abrt_action_save_package_data_SOURCES = \ rpm.h rpm.c \ Settings.h Settings.cpp \ - abrt-action-save-package-data.cpp + abrt-action-save-package-data.c abrt_action_save_package_data_CPPFLAGS = \ - -I$(srcdir)/../include \ + -I$(srcdir)/../include/report -I$(srcdir)/../include \ -I$(srcdir)/../lib \ -DBIN_DIR=\"$(bindir)\" \ -DVAR_RUN=\"$(VAR_RUN)\" \ @@ -96,7 +95,7 @@ abrt_action_save_package_data_CPPFLAGS = \ -Wall -Werror abrt_action_save_package_data_LDADD = \ $(RPM_LIBS) \ - ../lib/libabrt.la + ../lib/libreport.la dbusabrtconfdir = ${sysconfdir}/dbus-1/system.d/ dist_dbusabrtconf_DATA = dbus-abrt.conf diff --git a/src/daemon/MiddleWare.cpp b/src/daemon/MiddleWare.cpp index ee2853b2..2757d84f 100644 --- a/src/daemon/MiddleWare.cpp +++ b/src/daemon/MiddleWare.cpp @@ -19,32 +19,21 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" -#include "Daemon.h" #include "Settings.h" -#include "abrt_exception.h" #include "comm_layer_inner.h" -#include "CommLayerServer.h" +#include "CommLayerServerDBus.h" #include "MiddleWare.h" using namespace std; /** - * An instance of CPluginManager. When MiddleWare wants to do something - * with plugins, it calls the plugin manager. - * @see PluginManager.h - */ -CPluginManager* g_pPluginManager; - - -/** * Get one crash info. If getting is successful, * then crash info is filled. * @param dump_dir_name A dump dir containing all necessary data. * @param pCrashData A crash info. * @return It return results of operation. See mw_result_t. */ -static mw_result_t FillCrashInfo(const char *dump_dir_name, - map_crash_data_t& pCrashData); +static crash_data_t *FillCrashInfo(const char *dump_dir_name); /** * Transforms a debugdump directory to inner crash @@ -52,36 +41,53 @@ static mw_result_t FillCrashInfo(const char *dump_dir_name, * @param dump_dir_name A debugdump dir containing all necessary data. * @param pCrashData A created crash report. */ -static bool DebugDumpToCrashReport(const char *dump_dir_name, map_crash_data_t& pCrashData) +static crash_data_t *DebugDumpToCrashReport(const char *dump_dir_name) { VERB3 log(" DebugDumpToCrashReport('%s')", dump_dir_name); struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) - return false; - + return NULL; + + static const char *const must_have_files[] = { + FILENAME_ARCHITECTURE, + FILENAME_KERNEL , + FILENAME_PACKAGE , + FILENAME_COMPONENT , + FILENAME_OS_RELEASE , + FILENAME_EXECUTABLE , + NULL + }; const char *const *v = must_have_files; while (*v) { if (!dd_exist(dd, *v)) { + /* Old dump dir format compat. Remove in abrt-2.1 */ + if (strcmp(*v, FILENAME_OS_RELEASE) == 0) + if (dd_exist(dd, "release")) + goto ok; + dd_close(dd); log("Important file '%s/%s' is missing", dump_dir_name, *v); - return false; + return NULL; } + ok: v++; } - load_crash_data_from_crash_dump_dir(dd, pCrashData); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); char *events = list_possible_events(dd, NULL, ""); dd_close(dd); - add_to_crash_data_ext(pCrashData, CD_EVENTS, CD_SYS, CD_ISNOTEDITABLE, events); + add_to_crash_data_ext(crash_data, CD_EVENTS, events, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); free(events); - add_to_crash_data_ext(pCrashData, CD_DUMPDIR, CD_SYS, CD_ISNOTEDITABLE, dump_dir_name); + add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); - return true; + return crash_data; } static char *do_log_and_update_client(char *log_line, void *param) @@ -91,22 +97,36 @@ static char *do_log_and_update_client(char *log_line, void *param) return log_line; } +/** + * Takes care of getting all additional data needed + * for computing UUIDs and creating a report for particular analyzer + * plugin. This report could be send somewhere afterwards. If a creation + * is successful, then a crash report is filled. + * @param pAnalyzer A name of an analyzer plugin. + * @param pDebugDumpPath A debugdump dir containing all necessary data. + * @param pCrashData A filled crash report. + * @return It return results of operation. See mw_result_t. + */ /* * Called in two cases: * (1) by StartJob dbus call -> CreateReportThread(), in the thread * (2) by CreateReport dbus call */ -mw_result_t CreateCrashReport(const char *dump_dir_name, +static mw_result_t CreateCrashReport(const char *dump_dir_name, long caller_uid, int force, - map_crash_data_t& pCrashData) + crash_data_t **crash_data) { - VERB2 log("CreateCrashReport('%s',%ld,result)", dump_dir_name, caller_uid); + VERB2 log("CreateCrashReport('%s',%ld)", dump_dir_name, caller_uid); + + *crash_data = NULL; struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) return MW_NOENT_ERROR; + struct run_event_state *run_state; + int res; mw_result_t r = MW_OK; if (caller_uid != 0) /* not called by root */ @@ -131,63 +151,33 @@ mw_result_t CreateCrashReport(const char *dump_dir_name, } dd_close(dd); - try + run_state = new_run_event_state(); + run_state->logging_callback = do_log_and_update_client; + res = run_event_on_dir_name(run_state, dump_dir_name, force ? "reanalyze" : "analyze"); + free_run_event_state(run_state); + if (res != 0) { - struct run_event_state *run_state = new_run_event_state(); - run_state->logging_callback = do_log_and_update_client; - int res = run_event(run_state, dump_dir_name, force ? "reanalyze" : "analyze"); - free_run_event_state(run_state); - if (res != 0 && res != -1) /* -1 is "nothing was done", here it is ok */ - { - r = MW_PLUGIN_ERROR; - goto ret; - } - - /* Do a load_crash_data_from_crash_dump_dir from (possibly updated) - * crash dump dir - */ - if (!DebugDumpToCrashReport(dump_dir_name, pCrashData)) - { - error_msg("Error loading crash data"); - r = MW_ERROR; - goto ret; - } + r = MW_PLUGIN_ERROR; + goto ret; } - catch (CABRTException& e) + + /* Do a create_crash_data_from_dump_dir from (possibly updated) + * crash dump dir + */ + *crash_data = DebugDumpToCrashReport(dump_dir_name); + if (!*crash_data) { - r = MW_CORRUPTED; - error_msg("%s", e.what()); - if (e.type() == EXCEP_PLUGIN) - { - r = MW_PLUGIN_ERROR; - } + error_msg("Error loading crash data"); + r = MW_ERROR; } ret: + if (*crash_data == NULL) + *crash_data = new_crash_data(); VERB3 log("CreateCrashReport() returns %d", r); return r; } -void RunAction(const char *pActionDir, - const char *pPluginName, - const char *pPluginArgs) -{ - CAction* action = g_pPluginManager->GetAction(pPluginName); - if (!action) - { - /* GetAction() already complained */ - return; - } - try - { - action->Run(pActionDir, pPluginArgs, /*force:*/ 0); - } - catch (CABRTException& e) - { - error_msg("Execution of '%s' was not successful: %s", pPluginName, e.what()); - } -} - struct logging_state { char *last_line; }; @@ -205,43 +195,55 @@ static char *do_log_and_save_line(char *log_line, void *param) // Do not trust client_report here! // dbus handler passes it from user without checking -report_status_t Report(const map_crash_data_t& client_report, +report_status_t Report(crash_data_t *client_report, const vector_string_t& events, const map_map_string_t& settings, long caller_uid) { - // Get ID fields - const char *UID = get_crash_data_item_content_or_NULL(client_report, FILENAME_UID); - const char *dump_dir_name = get_crash_data_item_content_or_NULL(client_report, CD_DUMPDIR); - if (!UID || !dump_dir_name) + report_status_t ret; + const char *dump_dir_name = get_crash_item_content_or_NULL(client_report, CD_DUMPDIR); + if (!dump_dir_name) { - throw CABRTException(EXCEP_ERROR, "Report(): UID or DUMPDIR is missing in client's report data"); + update_client("Reporting error: %s", "DUMPDIR is missing in client's report data"); + ret[""].push_back("0"); // REPORT_STATUS_IDX_FLAG + ret[""].push_back("DUMPDIR is missing in client's report data"); // REPORT_STATUS_IDX_MSG + return ret; } // Retrieve corresponding stored record - map_crash_data_t stored_report; - mw_result_t r = FillCrashInfo(dump_dir_name, stored_report); - if (r != MW_OK) + crash_data_t *stored_report = FillCrashInfo(dump_dir_name); + if (!stored_report) { return report_status_t(); } // Is it allowed for this user to report? - if (caller_uid != 0 // not called by root - && strcmp(to_string(caller_uid).c_str(), UID) != 0 - ) { - const char *inform_all = get_crash_data_item_content_or_NULL(stored_report, FILENAME_INFORMALL); - if (!inform_all || !string_to_bool(inform_all)) - throw CABRTException(EXCEP_ERROR, "Report(): user with uid %ld can't report crash %s", - caller_uid, dump_dir_name); + if (caller_uid != 0) // not called by root + { + char caller_uid_str[sizeof(long)*3 + 2]; + sprintf(caller_uid_str, "%ld", caller_uid); + if (strcmp(caller_uid_str, get_crash_item_content_or_die(stored_report, FILENAME_UID)) != 0) + { + const char *inform_all = get_crash_item_content_or_NULL(stored_report, FILENAME_INFORMALL); + if (!inform_all || !string_to_bool(inform_all)) + { + free_crash_data(stored_report); + char *errmsg = xasprintf("user with uid %ld can't report crash %s", caller_uid, dump_dir_name); + update_client("Reporting error: %s", errmsg); + ret[""].push_back("0"); // REPORT_STATUS_IDX_FLAG + ret[""].push_back(errmsg); // REPORT_STATUS_IDX_MSG + free(errmsg); + return ret; + } + } } // Save comment, "how to reproduce", backtrace //TODO: we should iterate through stored_report and modify all //modifiable fields which have new data in client_report - const char *comment = get_crash_data_item_content_or_NULL(client_report, FILENAME_COMMENT); - const char *reproduce = get_crash_data_item_content_or_NULL(client_report, FILENAME_REPRODUCE); - const char *backtrace = get_crash_data_item_content_or_NULL(client_report, FILENAME_BACKTRACE); + const char *comment = get_crash_item_content_or_NULL(client_report, FILENAME_COMMENT); + const char *reproduce = get_crash_item_content_or_NULL(client_report, FILENAME_REPRODUCE); + const char *backtrace = get_crash_item_content_or_NULL(client_report, FILENAME_BACKTRACE); if (comment || reproduce || backtrace) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); @@ -250,45 +252,47 @@ report_status_t Report(const map_crash_data_t& client_report, if (comment) { dd_save_text(dd, FILENAME_COMMENT, comment); - add_to_crash_data_ext(stored_report, FILENAME_COMMENT, CD_TXT, CD_ISEDITABLE, comment); + add_to_crash_data_ext(stored_report, FILENAME_COMMENT, comment, CD_FLAG_TXT + CD_FLAG_ISEDITABLE); } if (reproduce) { dd_save_text(dd, FILENAME_REPRODUCE, reproduce); - add_to_crash_data_ext(stored_report, FILENAME_REPRODUCE, CD_TXT, CD_ISEDITABLE, reproduce); + add_to_crash_data_ext(stored_report, FILENAME_REPRODUCE, reproduce, CD_FLAG_TXT + CD_FLAG_ISEDITABLE); } if (backtrace) { dd_save_text(dd, FILENAME_BACKTRACE, backtrace); - add_to_crash_data_ext(stored_report, FILENAME_BACKTRACE, CD_TXT, CD_ISEDITABLE, backtrace); + add_to_crash_data_ext(stored_report, FILENAME_BACKTRACE, backtrace, CD_FLAG_TXT + CD_FLAG_ISEDITABLE); } dd_close(dd); } } /* Remove BIN filenames from stored_report if they are not present in client's data */ - map_crash_data_t::const_iterator its = stored_report.begin(); - while (its != stored_report.end()) + GHashTableIter iter; + char *name; + struct crash_item *value; + g_hash_table_iter_init(&iter, stored_report); + while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value)) { - if (its->second[CD_TYPE] == CD_BIN) + if (value->flags & CD_FLAG_BIN) { - std::string key = its->first; - if (get_crash_data_item_content_or_NULL(client_report, key.c_str()) == NULL) + if (get_crash_item_content_or_NULL(client_report, name) == NULL) { /* client does not have it -> does not want it passed to events */ - VERB3 log("Won't report BIN file %s:'%s'", key.c_str(), its->second[CD_CONTENT].c_str()); - its++; /* move off the element we will erase */ - stored_report.erase(key); + VERB3 log("Won't report BIN file %s:'%s'", name, value->content); + g_hash_table_iter_remove(&iter); continue; } } - its++; } VERB3 { - log_map_crash_data(client_report, " client_report"); - log_map_crash_data(stored_report, " stored_report"); + log_crash_data(client_report, " client_report"); + log_crash_data(stored_report, " stored_report"); } + free_crash_data(stored_report); +#define stored_report stored_report_must_not_be_used_below #define client_report client_report_must_not_be_used_below // Export overridden settings as environment variables @@ -310,7 +314,6 @@ report_status_t Report(const map_crash_data_t& client_report, // Run events bool at_least_one_reporter_succeeded = false; - report_status_t ret; std::string message; struct logging_state l_state; struct run_event_state *run_state = new_run_event_state(); @@ -321,10 +324,11 @@ report_status_t Report(const map_crash_data_t& client_report, std::string event = events[i]; l_state.last_line = NULL; - int r = run_event(run_state, dump_dir_name, event.c_str()); - if (r == -1) + int r = run_event_on_dir_name(run_state, dump_dir_name, event.c_str()); + if (r == 0 && run_state->children_count == 0) { l_state.last_line = xasprintf("Error: no processing is specified for event '%s'", event.c_str()); + r = -1; } if (r == 0) { @@ -390,6 +394,7 @@ report_status_t Report(const map_crash_data_t& client_report, } return ret; +#undef stored_report #undef client_report } @@ -470,8 +475,7 @@ static char *do_log(char *log_line, void *param) return log_line; } -mw_result_t LoadDebugDump(const char *dump_dir_name, - map_crash_data_t& pCrashData) +mw_result_t LoadDebugDump(const char *dump_dir_name, crash_data_t **crash_data) { mw_result_t res; @@ -492,7 +496,7 @@ mw_result_t LoadDebugDump(const char *dump_dir_name, run_state->post_run_callback = is_crash_a_dup; run_state->post_run_param = &state; run_state->logging_callback = do_log; - int r = run_event(run_state, dump_dir_name, "post-create"); + int r = run_event_on_dir_name(run_state, dump_dir_name, "post-create"); free_run_event_state(run_state); //TODO: consider this case: @@ -527,7 +531,7 @@ mw_result_t LoadDebugDump(const char *dump_dir_name, dump_dir_name = state.crash_dump_dup_name; } - /* Loads pCrashData (from the *first debugdump dir* if this one is a dup) + /* Loads crash_data (from the *first debugdump dir* if this one is a dup) * Returns: * MW_OCCURRED: "crash count is != 1" (iow: it is > 1 - dup) * MW_OK: "crash count is 1" (iow: this is a new crash, not a dup) @@ -548,9 +552,10 @@ mw_result_t LoadDebugDump(const char *dump_dir_name, dd_save_text(dd, FILENAME_COUNT, new_count_str); dd_close(dd); - res = FillCrashInfo(dump_dir_name, pCrashData); - if (res == MW_OK) + *crash_data = FillCrashInfo(dump_dir_name); + if (*crash_data != NULL) { + res = MW_OK; if (count > 1) { log("Crash dump is a duplicate of %s", dump_dir_name); @@ -568,99 +573,89 @@ mw_result_t LoadDebugDump(const char *dump_dir_name, return res; } -static mw_result_t FillCrashInfo(const char *dump_dir_name, - map_crash_data_t& pCrashData) +static crash_data_t *FillCrashInfo(const char *dump_dir_name) { struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) - return MW_ERROR; + return NULL; - load_crash_data_from_crash_dump_dir(dd, pCrashData); + crash_data_t *crash_data = create_crash_data_from_dump_dir(dd); char *events = list_possible_events(dd, NULL, ""); dd_close(dd); - add_to_crash_data_ext(pCrashData, CD_EVENTS, CD_SYS, CD_ISNOTEDITABLE, events); + add_to_crash_data_ext(crash_data, CD_EVENTS, events, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); free(events); - add_to_crash_data_ext(pCrashData, CD_DUMPDIR, CD_SYS, CD_ISNOTEDITABLE, dump_dir_name); + add_to_crash_data_ext(crash_data, CD_DUMPDIR, dump_dir_name, + CD_FLAG_TXT + CD_FLAG_ISNOTEDITABLE); - return MW_OK; + return crash_data; } -vector_map_crash_data_t GetCrashInfos(long caller_uid) +vector_of_crash_data_t *GetCrashInfos(long caller_uid) { - vector_map_crash_data_t retval; + vector_of_crash_data_t *retval = new_vector_of_crash_data(); log("Getting crash infos..."); DIR *dir = opendir(DEBUG_DUMPS_DIR); if (dir != NULL) { - try + struct dirent *dent; + while ((dent = readdir(dir)) != NULL) { - struct dirent *dent; - while ((dent = readdir(dir)) != NULL) - { - if (dot_or_dotdot(dent->d_name)) - continue; /* skip "." and ".." */ + if (dot_or_dotdot(dent->d_name)) + continue; /* skip "." and ".." */ - char *dump_dir_name = concat_path_file(DEBUG_DUMPS_DIR, dent->d_name); + char *dump_dir_name = concat_path_file(DEBUG_DUMPS_DIR, dent->d_name); - struct stat statbuf; - if (stat(dump_dir_name, &statbuf) != 0 - || !S_ISDIR(statbuf.st_mode) - ) { - goto next; /* not a dir, skip */ - } + struct stat statbuf; + if (stat(dump_dir_name, &statbuf) != 0 + || !S_ISDIR(statbuf.st_mode) + ) { + goto next; /* not a dir, skip */ + } - /* Skip directories which are not for this uid */ - if (caller_uid != 0) /* not called by root? */ - { - char *uid; - char caller_uid_str[sizeof(long) * 3 + 2]; + /* Skip directories which are not for this uid */ + if (caller_uid != 0) /* not called by root? */ + { + char *uid; + char caller_uid_str[sizeof(long) * 3 + 2]; - struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); - if (!dd) - goto next; + struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); + if (!dd) + goto next; - sprintf(caller_uid_str, "%ld", caller_uid); - uid = dd_load_text(dd, FILENAME_UID); - if (strcmp(uid, caller_uid_str) != 0) + sprintf(caller_uid_str, "%ld", caller_uid); + uid = dd_load_text(dd, FILENAME_UID); + if (strcmp(uid, caller_uid_str) != 0) + { + char *inform_all = dd_load_text_ext(dd, FILENAME_INFORMALL, DD_FAIL_QUIETLY); + bool for_all = string_to_bool(inform_all); + free(inform_all); + if (!for_all) { - char *inform_all = dd_load_text_ext(dd, FILENAME_INFORMALL, DD_FAIL_QUIETLY); - bool for_all = string_to_bool(inform_all); - free(inform_all); - if (!for_all) - { - dd_close(dd); - goto next; - } + dd_close(dd); + goto next; } - dd_close(dd); } + dd_close(dd); + } + { + crash_data_t *crash_data = FillCrashInfo(dump_dir_name); + if (!crash_data) { - map_crash_data_t info; - mw_result_t res = FillCrashInfo(dump_dir_name, info); - switch (res) - { - case MW_OK: - retval.push_back(info); - break; - case MW_ERROR: - error_msg("Dump directory %s doesn't exist or misses crucial files, deleting", dump_dir_name); - delete_crash_dump_dir(dump_dir_name); - break; - default: - break; - } + error_msg("Dump directory %s doesn't exist or misses crucial files, deleting", dump_dir_name); + delete_dump_dir(dump_dir_name); + } + else + { + g_ptr_array_add(retval, crash_data); } - next: - free(dump_dir_name); } - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); + next: + free(dump_dir_name); } closedir(dir); } @@ -676,14 +671,14 @@ vector_map_crash_data_t GetCrashInfos(long caller_uid) * StartJob dbus call already did all the processing, and we just retrieve * the result from dump directory, which is fast. */ -void CreateReport(const char* crash_id, long caller_uid, int force, map_crash_data_t& crashReport) +void CreateReport(const char* crash_id, long caller_uid, int force, crash_data_t **crash_data) { /* FIXME: starting from here, any shared data must be protected with a mutex. */ - mw_result_t res = CreateCrashReport(crash_id, caller_uid, force, crashReport); + mw_result_t res = CreateCrashReport(crash_id, caller_uid, force, crash_data); switch (res) { case MW_OK: - VERB2 log_map_crash_data(crashReport, "crashReport"); + VERB2 log_crash_data(*crash_data, "crashReport"); break; case MW_NOENT_ERROR: error_msg("Can't find crash with id '%s'", crash_id); @@ -715,18 +710,10 @@ static void* create_report(void* arg) /* Client name is per-thread, need to set it */ set_client_name(thread_data->peer); - try - { - log("Creating report..."); - map_crash_data_t crashReport; - CreateReport(thread_data->crash_id, thread_data->caller_uid, thread_data->force, crashReport); - g_pCommLayer->JobDone(thread_data->peer); - } - catch (CABRTException& e) - { - error_msg("%s", e.what()); - } - catch (...) {} + log("Creating report..."); + crash_data_t *crash_data = NULL; + CreateReport(thread_data->crash_id, thread_data->caller_uid, thread_data->force, &crash_data); + send_dbus_sig_JobDone(thread_data->peer); set_client_name(NULL); /* free strduped strings */ @@ -805,10 +792,10 @@ void GetPluginsInfo(map_map_string_t &map_of_plugin_info) struct dirent *dent; while ((dent = readdir(dir)) != NULL) { - if (!is_regular_file(dent, PLUGINS_CONF_DIR)) - continue; char *ext = strrchr(dent->d_name, '.'); - if (!ext || strcmp(ext + 1, PLUGINS_CONF_EXTENSION) != 0) + if (!ext || strcmp(ext + 1, "conf") != 0) + continue; + if (!is_regular_file(dent, PLUGINS_CONF_DIR)) continue; VERB3 log("Found %s", dent->d_name); *ext = '\0'; @@ -853,10 +840,12 @@ void GetPluginsInfo(map_map_string_t &map_of_plugin_info) closedir(dir); } -void GetPluginSettings(const char *plugin_name, map_plugin_settings_t &plugin_settings) +map_string_h *GetPluginSettings(const char *plugin_name) { char *conf_file = xasprintf(PLUGINS_CONF_DIR"/%s.conf", plugin_name); - if (LoadPluginSettings(conf_file, plugin_settings, /*skip w/o value:*/ false)) + map_string_h *settings = new_map_string(); + if (load_conf_file(conf_file, settings, /*skip w/o value:*/ false)) VERB3 log("Loaded %s.conf", plugin_name); free(conf_file); + return settings; } diff --git a/src/daemon/MiddleWare.h b/src/daemon/MiddleWare.h index 808d7be4..fde29978 100644 --- a/src/daemon/MiddleWare.h +++ b/src/daemon/MiddleWare.h @@ -23,7 +23,6 @@ #define MIDDLEWARE_H_ #include "abrt_types.h" -#include "PluginManager.h" /** * An enum contains all return codes. @@ -46,29 +45,6 @@ typedef enum { /** - * Takes care of getting all additional data needed - * for computing UUIDs and creating a report for particular analyzer - * plugin. This report could be send somewhere afterwards. If a creation - * is successful, then a crash report is filled. - * @param pAnalyzer A name of an analyzer plugin. - * @param pDebugDumpPath A debugdump dir containing all necessary data. - * @param pCrashData A filled crash report. - * @return It return results of operation. See mw_result_t. - */ -mw_result_t CreateCrashReport(const char *dump_dir_name, - long caller_uid, - int force, - map_crash_data_t& pCrashData); -/** - * Activates particular action plugin. - * @param pActionDir A directory, which is passed as working to a action plugin. - * @param pPluginName An action plugin name. - * @param pPluginArgs Action plugin's arguments. - */ -void RunAction(const char *pActionDir, - const char *pPluginName, - const char *pPluginArgs); -/** * Reports a crash report to particular receiver. It * takes an user uid, tries to find user config file and load it. If it * fails, then default config is used. If pUID is emply string, default @@ -76,16 +52,14 @@ void RunAction(const char *pActionDir, * ...). * @param crash_data * A crash report. - * @param reporters - * List of allowed reporters. Which reporters will be used depends - * on the analyzer of the crash_data. Reporters missing from this list - * will not be used. + * @param events + * List of events to run. * @param caller_uid * An user uid. * @return - * A report status, which reporters ends successfuly with messages. + * A report status: which events finished successfully, with messages. */ -report_status_t Report(const map_crash_data_t& crash_data, +report_status_t Report(crash_data_t *crash_data, const vector_string_t& events, const map_map_string_t& settings, long caller_uid); @@ -97,15 +71,14 @@ report_status_t Report(const map_crash_data_t& crash_data, * @param pCrashData A crash info. * @return It return results of operation. See mw_result_t. */ -mw_result_t LoadDebugDump(const char *dump_dir_name, - map_crash_data_t& pCrashData); +mw_result_t LoadDebugDump(const char *dump_dir_name, crash_data_t **crash_data); -vector_map_crash_data_t GetCrashInfos(long caller_uid); +vector_of_crash_data_t *GetCrashInfos(long caller_uid); int CreateReportThread(const char* dump_dir_name, long caller_uid, int force, const char* pSender); -void CreateReport(const char* dump_dir_name, long caller_uid, int force, map_crash_data_t&); +void CreateReport(const char* dump_dir_name, long caller_uid, int force, crash_data_t **crash_data); int DeleteDebugDump(const char *dump_dir_name, long caller_uid); void GetPluginsInfo(map_map_string_t &map_of_plugin_info); -void GetPluginSettings(const char *plugin_name, map_plugin_settings_t &plugin_settings); +map_string_h *GetPluginSettings(const char *plugin_name); #endif /*MIDDLEWARE_H_*/ diff --git a/src/daemon/PluginManager.cpp b/src/daemon/PluginManager.cpp deleted file mode 100644 index 665a4625..00000000 --- a/src/daemon/PluginManager.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - PluginManager.cpp - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - 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 <dlfcn.h> -#include "abrtlib.h" -#include "abrt_exception.h" -#include "PluginManager.h" - -using namespace std; - - -/** - * CLoadedModule class. A class which contains a loaded plugin. - */ -class CLoadedModule -{ - private: - /* dlopen'ed library */ - void *m_pHandle; - const plugin_info_t *m_pPluginInfo; - CPlugin* (*m_pFnPluginNew)(); - - public: - CLoadedModule(void *handle, const char *mod_name); - ~CLoadedModule() { dlclose(m_pHandle); } - int GetMagicNumber() { return m_pPluginInfo->m_nMagicNumber; } - const char *GetVersion() { return m_pPluginInfo->m_sVersion; } - const char *GetName() { return m_pPluginInfo->m_sName; } - const char *GetDescription() { return m_pPluginInfo->m_sDescription; } - const char *GetEmail() { return m_pPluginInfo->m_sEmail; } - const char *GetWWW() { return m_pPluginInfo->m_sWWW; } - const char *GetGTKBuilder() { return m_pPluginInfo->m_sGTKBuilder; } - plugin_type_t GetType() { return m_pPluginInfo->m_Type; } - CPlugin *PluginNew() { return m_pFnPluginNew(); } -}; -CLoadedModule::CLoadedModule(void *handle, const char *mod_name) -{ - m_pHandle = handle; - /* All errors are fatal */ -#define LOADSYM(fp, handle, name) \ - do { \ - fp = (typeof(fp)) (dlsym(handle, name)); \ - if (!fp) \ - error_msg_and_die("'%s' has no %s entry", mod_name, name); \ - } while (0) - - LOADSYM(m_pPluginInfo, handle, "plugin_info"); - LOADSYM(m_pFnPluginNew, handle, "plugin_new"); -#undef LOADSYM -} - - -/** - * Text representation of plugin types. - */ -static const char *const plugin_type_str[] = { - "Analyzer", - "Action", - "Reporter", - "Database" -}; - - -CPluginManager::CPluginManager() -{} - -CPluginManager::~CPluginManager() -{} - -void CPluginManager::LoadPlugins() -{ - DIR *dir = opendir(PLUGINS_LIB_DIR); - if (dir != NULL) - { - struct dirent *dent; - while ((dent = readdir(dir)) != NULL) - { - if (!is_regular_file(dent, PLUGINS_LIB_DIR)) - continue; - char *ext = strrchr(dent->d_name, '.'); - if (!ext || strcmp(ext + 1, PLUGINS_LIB_EXTENSION) != 0) - continue; - *ext = '\0'; - if (strncmp(dent->d_name, PLUGINS_LIB_PREFIX, sizeof(PLUGINS_LIB_PREFIX)-1) != 0) - continue; - LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1, /*enabled_only:*/ true); - } - closedir(dir); - } -} - -void CPluginManager::UnLoadPlugins() -{ - map_loaded_module_t::iterator it_module; - while ((it_module = m_mapLoadedModules.begin()) != m_mapLoadedModules.end()) - { - UnLoadPlugin(it_module->first.c_str()); - } -} - -CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only) -{ - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin != m_mapPlugins.end()) - { - return it_plugin->second; /* ok */ - } - - map_string_t plugin_info; - plugin_info["Name"] = pName; - - const char *conf_name = pName; - if (strncmp(pName, "Kerneloops", sizeof("Kerneloops")-1) == 0) - { - /* Kerneloops{,Scanner,Reporter} share the same .conf file */ - conf_name = "Kerneloops"; - } - map_plugin_settings_t pluginSettings; - string conf_fullname = ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name); - LoadPluginSettings(conf_fullname.c_str(), pluginSettings); - m_map_plugin_settings[pName] = pluginSettings; - /* If settings are empty, most likely .conf file does not exist. - * Don't mislead the user: */ - VERB3 if (!pluginSettings.empty()) log("Loaded %s.conf", conf_name); - - if (enabled_only) - { - map_plugin_settings_t::iterator it = pluginSettings.find("Enabled"); - if (it == pluginSettings.end() || !string_to_bool(it->second.c_str())) - { - plugin_info["Enabled"] = "no"; - string empty; - plugin_info["Type"] = empty; - plugin_info["Version"] = empty; - plugin_info["Description"] = empty; - plugin_info["Email"] = empty; - plugin_info["WWW"] = empty; - plugin_info["GTKBuilder"] = empty; - VERB3 log("Plugin %s: 'Enabled' is not set, not loading it (yet)", pName); - return NULL; /* error */ - } - } - - string libPath = ssprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName); - void *handle = dlopen(libPath.c_str(), RTLD_NOW); - if (!handle) - { - error_msg("Can't load '%s': %s", libPath.c_str(), dlerror()); - return NULL; /* error */ - } - CLoadedModule *module = new CLoadedModule(handle, pName); - if (module->GetMagicNumber() != PLUGINS_MAGIC_NUMBER - || module->GetType() < 0 - || module->GetType() > MAX_PLUGIN_TYPE - ) { - error_msg("Can't load non-compatible plugin %s: magic %d != %d or type %d is not in [0,%d]", - pName, - module->GetMagicNumber(), PLUGINS_MAGIC_NUMBER, - module->GetType(), MAX_PLUGIN_TYPE); - delete module; - return NULL; /* error */ - } - VERB3 log("Loaded plugin %s v.%s", pName, module->GetVersion()); - - CPlugin *plugin = NULL; - try - { - plugin = module->PluginNew(); - plugin->Init(); - plugin->SetSettings(pluginSettings); - } - catch (CABRTException& e) - { - error_msg("Can't initialize plugin %s: %s", - pName, - e.what() - ); - delete plugin; - delete module; - return NULL; /* error */ - } - - plugin_info["Enabled"] = "yes"; - plugin_info["Type"] = plugin_type_str[module->GetType()]; - //plugin_info["Name"] = module->GetName(); - plugin_info["Version"] = module->GetVersion(); - plugin_info["Description"] = module->GetDescription(); - plugin_info["Email"] = module->GetEmail(); - plugin_info["WWW"] = module->GetWWW(); - plugin_info["GTKBuilder"] = module->GetGTKBuilder(); - - m_mapLoadedModules[pName] = module; - m_mapPlugins[pName] = plugin; - log("Registered %s plugin '%s'", plugin_type_str[module->GetType()], pName); - return plugin; /* ok */ -} - -void CPluginManager::UnLoadPlugin(const char *pName) -{ - map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); - if (it_module != m_mapLoadedModules.end()) - { - map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName); - if (it_plugin != m_mapPlugins.end()) /* always true */ - { - it_plugin->second->DeInit(); - delete it_plugin->second; - m_mapPlugins.erase(it_plugin); - } - log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName); - delete it_module->second; - m_mapLoadedModules.erase(it_module); - } -} - -CAction* CPluginManager::GetAction(const char *pName, bool silent) -{ - CPlugin *plugin = LoadPlugin(pName); - if (!plugin) - { - error_msg("Plugin '%s' is not registered", pName); - return NULL; - } - if (m_mapLoadedModules[pName]->GetType() != ACTION) - { - if (!silent) - error_msg("Plugin '%s' is not an action plugin", pName); - return NULL; - } - return (CAction*)plugin; -} - -plugin_type_t CPluginManager::GetPluginType(const char *pName) -{ - CPlugin *plugin = LoadPlugin(pName); - if (!plugin) - { - throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName); - } - map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName); - return it_module->second->GetType(); -} diff --git a/src/daemon/PluginManager.h b/src/daemon/PluginManager.h deleted file mode 100644 index c5036fbf..00000000 --- a/src/daemon/PluginManager.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - PluginManager.h - header file for plugin manager. it takes care about - (un)loading plugins - - Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com) - 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. -*/ -#ifndef PLUGINMANAGER_H_ -#define PLUGINMANAGER_H_ - -#include "abrt_types.h" -#include "plugin.h" -#include "analyzer.h" -#include "action.h" - -class CLoadedModule; /* opaque */ - -/** - * A class. It takes care of loading, registering and manipulating with - * plugins. When a plugin is loaded, its library is opened, but no plugin - * instance is created. It is possible after plugin registration. - */ -class CPluginManager -{ - private: - typedef std::map<std::string, CLoadedModule*> map_loaded_module_t; - typedef std::map<std::string, CPlugin*> map_plugin_t; - - /** - * Loaded plugins. A key is a plugin name. - */ - map_loaded_module_t m_mapLoadedModules; - /** - * Registered plugins. A key is a plugin name. - */ - map_plugin_t m_mapPlugins; - /** - * List of all possible plugins (loaded or not), with some attributes. - */ - map_map_string_t m_map_plugin_settings; - - public: - /** - * A constructor. - * @param pPluginsConfDir A plugins configuration directory. - * @param pPluginsLibDir A plugins library directory. - */ - CPluginManager(); - /** - * A destructor. - */ - ~CPluginManager(); - /** - * A method, which loads all plugins in plugins library direcotry. - */ - void LoadPlugins(); - /** - * A method, which unregister and unload all loaded plugins. - */ - void UnLoadPlugins(); - /** - * A method, which loads particular plugin. - * @param pName A plugin name. - */ - CPlugin* LoadPlugin(const char *pName, bool enabled_only = false); - /** - * A method, which unloads particular plugin. - * @param pName A plugin name. - */ - void UnLoadPlugin(const char *pName); - /** - * A method, which returns instance of particular action plugin. - * @param pName A plugin name. - * @return An action plugin. - */ - CAction* GetAction(const char *pName, bool silent = false); - /** - * A method, which returns type of particular plugin. - * @param pName A plugin name. - * @return A plugin type. - */ - plugin_type_t GetPluginType(const char *pName); -}; - -#endif /*PLUGINMANAGER_H_*/ diff --git a/src/daemon/Settings.cpp b/src/daemon/Settings.cpp index 5b9972ba..e25b7959 100644 --- a/src/daemon/Settings.cpp +++ b/src/daemon/Settings.cpp @@ -19,8 +19,8 @@ #include "abrtlib.h" #include "Settings.h" -#define SECTION_COMMON "Common" -#define SECTION_CRON "Cron" +#define SECTION_COMMON "Common" +#define SECTION_LOG_SCANNERS "LogScanners" /* Conf file has this format: * [ section_name1 ] @@ -31,32 +31,28 @@ */ /* Static data */ -/* Filled by LoadSettings() */ +/* Filled by load_settings() */ /* map["name"] = "value" strings from [ Common ] section. * If the same name found on more than one line, * the values are appended, separated by comma: map["name"] = "value1,value2" */ static map_string_t s_mapSectionCommon; -/* ... from [ Cron ] */ -static map_string_t s_mapSectionCron; /* Public data */ -/* Written out exactly in this order by SaveSettings() */ /* [ Common ] */ /* one line: "OpenGPGCheck = value" */ bool g_settings_bOpenGPGCheck = false; /* one line: "OpenGPGPublicKeys = value1,value2" */ -GList *g_settings_setOpenGPGPublicKeys = NULL; -GList *g_settings_setBlackListedPkgs = NULL; -GList *g_settings_setBlackListedPaths = NULL; -char *g_settings_sWatchCrashdumpArchiveDir = NULL; +GList * g_settings_setOpenGPGPublicKeys = NULL; +GList * g_settings_setBlackListedPkgs = NULL; +GList * g_settings_setBlackListedPaths = NULL; +char * g_settings_sWatchCrashdumpArchiveDir = NULL; unsigned int g_settings_nMaxCrashReportsSize = 1000; bool g_settings_bProcessUnpackaged = false; -/* [ Cron ] */ -/* many lines, one per key: "map_key = aa_first,bb_first(bb_second),cc_first" */ -map_cron_t g_settings_mapCron; +/* [ LogScanners ] */ +char * g_settings_sLogScanners = NULL; /* @@ -80,107 +76,12 @@ static GList *parse_list(const char* list) } if (item->len > 0) - l = g_list_append(l, xstrdup(item->buf)); + l = g_list_append(l, xstrdup(item->buf)); strbuf_free(item); return l; } -/* Format: name, name(param),name("param with spaces \"and quotes\"") */ -static vector_pair_string_string_t ParseListWithArgs(const char *pValue, int *err) -{ - VERB3 log(" ParseListWithArgs(%s)", pValue); - - vector_pair_string_string_t pluginsWithArgs; - std::string item; - std::string action; - bool is_quote = false; - bool is_arg = false; - for (int ii = 0; pValue[ii]; ii++) - { - if (is_quote && pValue[ii] == '\\' && pValue[ii + 1]) - { - ii++; - item += pValue[ii]; - continue; - } - if (pValue[ii] == '"') - { - is_quote = !is_quote; - /*item += pValue[ii]; - wrong! name("param") must be == name(param) */ - continue; - } - if (is_quote) - { - item += pValue[ii]; - continue; - } - if (pValue[ii] == '(') - { - if (!is_arg) - { - action = item; - item = ""; - is_arg = true; - } - else - { - *err = 1; - error_msg("Parser error: Invalid syntax on column %d in \"%s\"", ii, pValue); - } - - continue; - } - if (pValue[ii] == ')') - { - if (is_arg) - { - VERB3 log(" adding (%s,%s)", action.c_str(), item.c_str()); - pluginsWithArgs.push_back(make_pair(action, item)); - item = ""; - is_arg = false; - action = ""; - } - else - { - *err = 1; - error_msg("Parser error: Invalid syntax on column %d in \"%s\"", ii, pValue); - } - - continue; - } - if (pValue[ii] == ',' && !is_arg) - { - if (item != "") - { - VERB3 log(" adding (%s,%s)", item.c_str(), ""); - pluginsWithArgs.push_back(make_pair(item, "")); - item = ""; - } - continue; - } - item += pValue[ii]; - } - - if (is_quote) - { - *err = 1; - error_msg("Parser error: Unclosed quote in \"%s\"", pValue); - } - - if (is_arg) - { - *err = 1; - error_msg("Parser error: Unclosed argument in \"%s\"", pValue); - } - else if (item != "") - { - VERB3 log(" adding (%s,%s)", item.c_str(), ""); - pluginsWithArgs.push_back(make_pair(item, "")); - } - return pluginsWithArgs; -} - static int ParseCommon() { map_string_t::const_iterator end = s_mapSectionCommon.end(); @@ -207,7 +108,7 @@ static int ParseCommon() it = s_mapSectionCommon.find("MaxCrashReportsSize"); if (it != end) { - g_settings_nMaxCrashReportsSize = xatoi_u(it->second.c_str()); + g_settings_nMaxCrashReportsSize = xatoi_positive(it->second.c_str()); } it = s_mapSectionCommon.find("ProcessUnpackaged"); if (it != end) @@ -217,20 +118,6 @@ static int ParseCommon() return 0; /* no error */ } -static int ParseCron() -{ - map_string_t::iterator it = s_mapSectionCron.begin(); - for (; it != s_mapSectionCron.end(); it++) - { - int err = 0; - vector_pair_string_string_t actionsAndReporters = ParseListWithArgs(it->second.c_str(), &err); - if (err) - return err; - g_settings_mapCron[it->first] = actionsAndReporters; - } - return 0; /* no error */ -} - static void LoadGPGKeys() { FILE *fp = fopen(CONF_DIR"/gpg_keys", "r"); @@ -277,7 +164,7 @@ static int ReadConfigurationFromFile(FILE *fp) value += line[ii]; continue; } - if (isspace(line[ii]) && !is_quote) + if (isspace(line[ii]) && !is_quote && is_key) { continue; } @@ -304,8 +191,9 @@ static int ReadConfigurationFromFile(FILE *fp) section += line[ii]; continue; } - if (line[ii] == '=' && !is_quote) + if (is_key && line[ii] == '=' && !is_quote) { + while (isspace(line[ii + 1])) ii++; is_key = false; key = value; value = ""; @@ -351,11 +239,9 @@ static int ReadConfigurationFromFile(FILE *fp) s_mapSectionCommon[key] += ","; s_mapSectionCommon[key] += value; } - else if (section == SECTION_CRON) + else if (section == SECTION_LOG_SCANNERS) { - if (s_mapSectionCron[key] != "") - s_mapSectionCron[key] += ","; - s_mapSectionCron[key] += value; + g_settings_sLogScanners = xstrdup(value.c_str()); } else { @@ -372,7 +258,7 @@ static int ReadConfigurationFromFile(FILE *fp) } /* abrt daemon loads .conf file */ -int LoadSettings() +int load_settings() { int err = 0; @@ -387,8 +273,6 @@ int LoadSettings() if (err == 0) err = ParseCommon(); - if (err == 0) - err = ParseCron(); if (err == 0) { @@ -411,49 +295,36 @@ map_abrt_settings_t GetSettings() map_abrt_settings_t ABRTSettings; ABRTSettings[SECTION_COMMON] = s_mapSectionCommon; - ABRTSettings[SECTION_CRON] = s_mapSectionCron; return ABRTSettings; } -/* dbus call to change some .conf file data */ -void SetSettings(const map_abrt_settings_t& pSettings, const char *dbus_sender) +///* dbus call to change some .conf file data */ +//void SetSettings(const map_abrt_settings_t& pSettings, const char *dbus_sender) +//{ +// map_abrt_settings_t::const_iterator it = pSettings.find(SECTION_COMMON); +// map_abrt_settings_t::const_iterator end = pSettings.end(); +// if (it != end) +// { +// s_mapSectionCommon = it->second; +// ParseCommon(); +// } +//} + +void free_settings() { - map_abrt_settings_t::const_iterator it = pSettings.find(SECTION_COMMON); - map_abrt_settings_t::const_iterator end = pSettings.end(); - if (it != end) - { - s_mapSectionCommon = it->second; - ParseCommon(); - } - it = pSettings.find(SECTION_CRON); - if (it != end) - { - s_mapSectionCron = it->second; - ParseCron(); - } -} - -void settings_free() -{ - for (GList *li = g_settings_setOpenGPGPublicKeys; li != NULL; li = g_list_next(li)) - free((char*)li->data); - - g_list_free(g_settings_setOpenGPGPublicKeys); + list_free_with_free(g_settings_setOpenGPGPublicKeys); g_settings_setOpenGPGPublicKeys = NULL; - for (GList *li = g_settings_setBlackListedPkgs; li != NULL; li = g_list_next(li)) - free((char*)li->data); - - g_list_free(g_settings_setBlackListedPkgs); + list_free_with_free(g_settings_setBlackListedPkgs); g_settings_setBlackListedPkgs = NULL; - for (GList *li = g_settings_setBlackListedPaths; li != NULL; li = g_list_next(li)) - free((char*)li->data); - - g_list_free(g_settings_setBlackListedPaths); + list_free_with_free(g_settings_setBlackListedPaths); g_settings_setBlackListedPaths = NULL; free(g_settings_sWatchCrashdumpArchiveDir); g_settings_sWatchCrashdumpArchiveDir = NULL; + + free(g_settings_sLogScanners); + g_settings_sLogScanners = NULL; } diff --git a/src/daemon/Settings.h b/src/daemon/Settings.h index 71824c74..dce6407d 100644 --- a/src/daemon/Settings.h +++ b/src/daemon/Settings.h @@ -20,25 +20,33 @@ #define SETTINGS_H_ #include "abrt_types.h" -#include <glib.h> -typedef map_vector_pair_string_string_t map_cron_t; +#ifdef __cplusplus + typedef map_map_string_t map_abrt_settings_t; +// looks unused to me. +// Ok to grep for SetSettings and delete after 2011-04-01. +// void SetSettings(const map_abrt_settings_t& pSettings, const char *dbus_sender); +map_abrt_settings_t GetSettings(); + +extern "C" { +#endif -extern GList *g_settings_setOpenGPGPublicKeys; -extern GList *g_settings_setBlackListedPkgs; -extern GList *g_settings_setBlackListedPaths; +extern GList * g_settings_setOpenGPGPublicKeys; +extern GList * g_settings_setBlackListedPkgs; +extern GList * g_settings_setBlackListedPaths; extern unsigned int g_settings_nMaxCrashReportsSize; extern bool g_settings_bOpenGPGCheck; extern bool g_settings_bProcessUnpackaged; -extern char *g_settings_sWatchCrashdumpArchiveDir; -extern map_cron_t g_settings_mapCron; +extern char * g_settings_sWatchCrashdumpArchiveDir; -int LoadSettings(); -void SaveSettings(); -void SetSettings(const map_abrt_settings_t& pSettings, const char * dbus_sender); -map_abrt_settings_t GetSettings(); +extern char * g_settings_sLogScanners; + +int load_settings(); +void free_settings(); -void settings_free(); +#ifdef __cplusplus +} +#endif #endif diff --git a/src/daemon/abrt-action-save-package-data.cpp b/src/daemon/abrt-action-save-package-data.c index cb880bd3..5be712cf 100644 --- a/src/daemon/abrt-action-save-package-data.cpp +++ b/src/daemon/abrt-action-save-package-data.c @@ -91,7 +91,6 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) char *package_short_name = NULL; char *component = NULL; char *script_name = NULL; /* only if "interpreter /path/to/script" */ - char *dsc = NULL; /* note: "goto ret" statements below free all the above variables, * but they don't dd_close(dd) */ @@ -100,7 +99,6 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) component = xstrdup("kernel"); package_full_name = xstrdup("kernel"); package_short_name = xstrdup("kernel"); - dsc = rpm_get_description(package_short_name); } else { @@ -124,21 +122,7 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) if (!dd) goto ret; /* return 1 (failure) */ dd_save_text(dd, FILENAME_PACKAGE, ""); - dd_save_text(dd, FILENAME_DESCRIPTION, "Crashed executable does not belong to any installed package"); dd_save_text(dd, FILENAME_COMPONENT, ""); -//TODO: move hostname saving to a more logical place - if (!remote) - { - char host[HOST_NAME_MAX + 1]; - int ret = gethostname(host, HOST_NAME_MAX); - if (ret < 0) - { - perror_msg("gethostname"); - host[0] = '\0'; - } - host[HOST_NAME_MAX] = '\0'; - dd_save_text(dd, FILENAME_HOSTNAME, host); - } goto ret0; /* no error */ } log("Executable '%s' doesn't belong to any package", executable); @@ -220,7 +204,6 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) } component = rpm_get_component(executable); - dsc = rpm_get_description(package_short_name); dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) @@ -231,27 +214,10 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) { dd_save_text(dd, FILENAME_PACKAGE, package_full_name); } - if (dsc) - { - dd_save_text(dd, FILENAME_DESCRIPTION, dsc); - } if (component) { dd_save_text(dd, FILENAME_COMPONENT, component); } -//TODO: move hostname saving to a more logical place - if (!remote) - { - char host[HOST_NAME_MAX + 1]; - int ret = gethostname(host, HOST_NAME_MAX); - if (ret < 0) - { - perror_msg("gethostname"); - host[0] = '\0'; - } - host[HOST_NAME_MAX] = '\0'; - dd_save_text(dd, FILENAME_HOSTNAME, host); - } dd_close(dd); @@ -262,41 +228,40 @@ static int SavePackageDescriptionToDebugDump(const char *dump_dir_name) free(package_short_name); free(component); free(script_name); - free(dsc); return error; } -static const char *dump_dir_name = "."; -static const char abrt_action_save_package_data_usage[] = - PROGNAME" [options] -d DIR\n" - "\n" - "Query package database and save package name, component, and description"; -enum { - OPT_v = 1 << 0, - OPT_d = 1 << 1, - OPT_s = 1 << 2, -}; -/* Keep enum above and order of options below in sync! */ -static struct options abrt_action_save_package_data_options[] = { - OPT__VERBOSE(&g_verbose), - OPT_STRING('d', NULL, &dump_dir_name, "DIR", "Crash dump directory"), - OPT_BOOL( 's', NULL, NULL, "Log to syslog"), - OPT_END() -}; - int main(int argc, char **argv) { char *env_verbose = getenv("ABRT_VERBOSE"); if (env_verbose) g_verbose = atoi(env_verbose); - unsigned opts = parse_opts(argc, argv, abrt_action_save_package_data_options, - abrt_action_save_package_data_usage); + const char *dump_dir_name = "."; + + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [options] -d DIR\n" + "\n" + "Query package database and save package name, component, and description" + ); + enum { + OPT_v = 1 << 0, + OPT_d = 1 << 1, + OPT_s = 1 << 2, + }; + /* Keep enum above and order of options below in sync! */ + struct options program_options[] = { + OPT__VERBOSE(&g_verbose), + OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Crash dump directory")), + OPT_BOOL( 's', NULL, NULL , _("Log to syslog")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); msg_prefix = PROGNAME; - if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); @@ -304,8 +269,8 @@ int main(int argc, char **argv) } VERB1 log("Loading settings"); - if (LoadSettings() != 0) - return 1; /* syntax error (looged already by LoadSettings) */ + if (load_settings() != 0) + return 1; /* syntax error (logged already by load_settings) */ VERB1 log("Initializing rpm library"); rpm_init(); diff --git a/src/daemon/abrt-handle-crashdump.c b/src/daemon/abrt-handle-crashdump.c index 2217c67a..e7847c5f 100644 --- a/src/daemon/abrt-handle-crashdump.c +++ b/src/daemon/abrt-handle-crashdump.c @@ -38,11 +38,13 @@ int main(int argc, char **argv) if (env_verbose) g_verbose = atoi(env_verbose); - const char *program_usage = _( + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( PROGNAME" [-vs]" /*" [-c CONFFILE]"*/ " -d DIR -e EVENT\n" " or: "PROGNAME" [-vs]" /*" [-c CONFFILE]"*/ " [-d DIR] -l[PFX]\n" "\n" - "Handle crash dump according to rules in abrt_event.conf"); + "Handle crash dump according to rules in abrt_event.conf" + ); enum { OPT_v = 1 << 0, OPT_s = 1 << 1, @@ -61,11 +63,12 @@ int main(int argc, char **argv) // OPT_STRING( 'c', NULL, &conf_filename, "CONFFILE", _("Configuration file" )), OPT_END() }; - - unsigned opts = parse_opts(argc, argv, program_options, program_usage); + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); if (!(opts & (OPT_e|OPT_l))) - parse_usage_and_die(program_usage, program_options); + show_usage_and_die(program_usage_string, program_options); + putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); + msg_prefix = PROGNAME; if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); @@ -87,17 +90,10 @@ int main(int argc, char **argv) /* -e EVENT: run event */ - /* Need to add LIBEXEC_DIR to PATH, because otherwise abrt-action-* - * are not found by exec() - */ - const char *env_path = getenv("PATH"); - if (!env_path) env_path = ""; - putenv(xasprintf("PATH=%s%s%s", LIBEXEC_DIR, (!env_path[0] ? "" : ":"), env_path)); - struct run_event_state *run_state = new_run_event_state(); run_state->logging_callback = do_log; - int r = run_event(run_state, dump_dir_name ? dump_dir_name : ".", event); - if (r == -1) + int r = run_event_on_dir_name(run_state, dump_dir_name ? dump_dir_name : ".", event); + if (r == 0 && run_state->children_count == 0) error_msg_and_die("No actions are found for event '%s'", event); free_run_event_state(run_state); diff --git a/src/daemon/abrt-server.c b/src/daemon/abrt-server.c index fdf66e59..de22f427 100644 --- a/src/daemon/abrt-server.c +++ b/src/daemon/abrt-server.c @@ -16,11 +16,10 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "abrtlib.h" -#include "dump_dir.h" -#include "abrt_crash_dump.h" /* FILENAME_foo */ #include "hooklib.h" #include "parse_options.h" +#define PROGNAME "abrt-server" /* Maximal length of backtrace. */ #define MAX_BACKTRACE_SIZE (1024*1024) @@ -108,9 +107,9 @@ static void create_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", + char *path = xasprintf(DEBUG_DUMPS_DIR"/%s-%s-%u.new", dir_basename, - (long)time(NULL), + iso_date_string(NULL), pid); /* No need to check the path length, as all variables used are limited, and dd_create() fails if the path is too long. */ @@ -120,6 +119,7 @@ static void create_debug_dump() { error_msg_and_die("Error creating crash dump %s", path); } + dd_create_basic_files(dd, client_uid); dd_save_text(dd, FILENAME_ANALYZER, analyzer); dd_save_text(dd, FILENAME_EXECUTABLE, executable); @@ -275,31 +275,32 @@ static void process_message(const char *message) static void dummy_handler(int sig_unused) {} -static const char abrt_server_usage[] = "abrt-server [options]"; -enum { - OPT_v = 1 << 0, - OPT_u = 1 << 1, - OPT_s = 1 << 2, -}; -/* Keep enum above and order of options below in sync! */ -static struct options abrt_server_options[] = { - OPT__VERBOSE(&g_verbose), - OPT_INTEGER( 'u' , 0, &client_uid, "Use UID as client uid"), - OPT_BOOL( 's' , 0, NULL, "Log to syslog"), - OPT_END() -}; - int main(int argc, char **argv) { char *env_verbose = getenv("ABRT_VERBOSE"); if (env_verbose) g_verbose = atoi(env_verbose); - unsigned opts = parse_opts(argc, argv, abrt_server_options, - abrt_server_usage); + /* Can't keep these strings/structs static: _() doesn't support that */ + const char *program_usage_string = _( + PROGNAME" [options]" + ); + enum { + OPT_v = 1 << 0, + OPT_u = 1 << 1, + OPT_s = 1 << 2, + }; + /* Keep enum above and order of options below in sync! */ + struct options program_options[] = { + OPT__VERBOSE(&g_verbose), + OPT_INTEGER('u', NULL, &client_uid, _("Use UID as client uid")), + OPT_BOOL( 's', NULL, NULL , _("Log to syslog")), + OPT_END() + }; + unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); putenv(xasprintf("ABRT_VERBOSE=%u", g_verbose)); - msg_prefix = xasprintf("abrt-server[%u]", getpid()); + msg_prefix = xasprintf(PROGNAME"[%u]", getpid()); if (opts & OPT_s) { openlog(msg_prefix, 0, LOG_DAEMON); diff --git a/src/daemon/abrt.conf b/src/daemon/abrt.conf index 07ea51a0..7f5a9c58 100644 --- a/src/daemon/abrt.conf +++ b/src/daemon/abrt.conf @@ -8,7 +8,7 @@ OpenGPGCheck = yes # Blacklisted packages # -BlackList = nspluginwrapper, valgrind, strace +BlackList = nspluginwrapper,valgrind,strace # Process crashes in executables which do not belong to any package? # @@ -16,7 +16,7 @@ ProcessUnpackaged = no # Blacklisted executable paths (shell patterns) # -BlackListedPaths = /usr/share/doc/*, */example* +BlackListedPaths = /usr/share/doc/*,*/example* # Enable this if you want abrtd to auto-unpack crashdump tarballs which appear # in this directory (for example, uploaded via ftp, scp etc). @@ -30,12 +30,7 @@ BlackListedPaths = /usr/share/doc/*, */example* MaxCrashReportsSize = 1000 -# Which Action plugins to run repeatedly +# So far we support only one line here # -[ Cron ] -# h:m - at h:m -# s - every s seconds - -120 = KerneloopsScanner - -#02:00 = FileTransfer +[ LogScanners ] +abrt-dump-oops = abrt-dump-oops -drw /var/log/messages diff --git a/src/daemon/abrt.conf.5 b/src/daemon/abrt.conf.5 index 3f9d8c39..84c8f002 100644 --- a/src/daemon/abrt.conf.5 +++ b/src/daemon/abrt.conf.5 @@ -65,18 +65,6 @@ all the C/C++ programs. .TP .B Kerneloops = \fIplugin\fP This plugin will be used in the case of kernel crashes. -.SS [ Cron ] -This section specifies tasks that will be run at some specified time. You can specify -either a time of day in the format -.br -.B hh:mm = \fIplugin\fP -.br -or an interval -.br -.B ss = \fIplugin2\fP -.br -in this case, \fIplugin2\fP will be run every \fIss\fP seconds (this number -can be greater than 60). .SH "SEE ALSO" .IR abrtd (8), .IR abrt-plugins (7) diff --git a/src/daemon/abrt_event.conf b/src/daemon/abrt_event.conf index 45c9017a..23765718 100644 --- a/src/daemon/abrt_event.conf +++ b/src/daemon/abrt_event.conf @@ -1,33 +1,49 @@ -# This table specifies which programs should be run +# This configuration file specifies which programs should be run # when the specified event occurs in crash dump lifetime. # # Example: # EVENT=post-create { pwd; date; }>/tmp/dt; echo $HOSTNAME `uname -r` # -# Each line may have conditions to be checked -# before the program is run. +# Rule starts with a line with non-space leading character. +# All subsequent lines which start with space or tab form one rule. +# Note that separating newline is *retained*. Example: +# EVENT=post-create date >/tmp/dt # semicolon is not needed here! +# echo $HOSTNAME `uname -r` +# +# Rules may be commented out with #. One # is sufficient to comment out +# even a multi-line rule (no need to comment out every line). +# +# Rule of the form "include GLOB_PATTERN" recurses to each file which matches +# GLOB_PATTERN. Example: "include post-create.d/*.conf" +# + +include events.d/*.conf + +# Any other rules specify which programs to run on the crash dump. +# +# Each rule may have conditions to be checked before the program is run. # # Conditions have form VAR=VAL, where VAR is either word "EVENT" # or a name of crash dump element to be checked (for example, # "executable", "package", hostname" etc). # -# If all conditions match, the program is run in the shell. +# If all conditions match, the remaining part of the rule +# (the "program" part) is run in the shell. # All shell language constructs are valid. # All stdout and stderr output is captured and passed to abrt # and possibly to abrt's frontends and shown to the user. # -# If the program terminates with nonzero exitcode, +# If the program terminates with nonzero exit code, # the event processing is considered unsuccessful and is stopped. # Last captured output line, if any, is considered to be # the error message indicating the reason of the failure, # and may be used by abrt as such. # -# If the program terminates successfully, next line is read +# If the program terminates successfully, next rule is read # and processed. This process is repeated until the end of this file. # abrt-action-analyze-c needs package name, save package data first EVENT=post-create abrt-action-save-package-data -EVENT=post-create analyzer=CCpp abrt-action-analyze-c EVENT=post-create analyzer=Python abrt-action-analyze-python EVENT=post-create analyzer=Kerneloops abrt-action-analyze-oops # If you want all users (not just root) to be able to see oopses: @@ -38,24 +54,20 @@ EVENT=post-create analyzer=Kerneloops abrt-action-analyze-oops # user interaction, uncomment this line: #EVENT=post-create analyzer=Kerneloops abrt-action-kerneloops # Example: if you want to save sosreport immediately at the moment of a crash: -#EVENT=post-create nice sosreport --tmp-dir "$DUMP_DIR" --batch --only=anaconda --only=bootloader --only=devicemapper --only=filesys --only=hardware --only=kernel --only=libraries --only=memory --only=networking --only=nfsserver --only=pam --only=process --only=rpm -k rpm.rpmva=off --only=ssh --only=startup --only=yum && { rm sosreport*.md5; mv sosreport*.tar.bz2 sosreport.tar.bz2; mv sosreport*.tar.xz sosreport.tar.xz; true; } 2>/dev/null - -#TODO: implement this (or add this functionality to abrt-action-install-debuginfo): -#EVENT=analyze analyzer=CCpp backtrace= trim-debuginfo-cache /var/cache/abrt-di 4096m -# Additional directories to search for debuginfos can be specified -# in the third argument (its format is CACHEDIR[:DEBUGINFODIR...]). -# For example, you can specify a network-mounted shared store -# of all debuginfos this way. -EVENT=analyze analyzer=CCpp backtrace= abrt-action-install-debuginfo.py "--core=$DUMP_DIR/coredump" "--tmpdir=/var/run/abrt/$$-$RANDOM" --cache=/var/cache/abrt-di -EVENT=analyze analyzer=CCpp backtrace= abrt-action-generate-backtrace - -# Same as "analyze", but executed when user requests "refresh" in GUI -#EVENT=reanalyze analyzer=CCpp trim-debuginfo-cache /var/cache/abrt-di 4096m -EVENT=reanalyze analyzer=CCpp abrt-action-install-debuginfo.py "--core=$DUMP_DIR/coredump" "--tmpdir=/var/run/abrt/$$-$RANDOM" --cache=/var/cache/abrt-di -EVENT=reanalyze analyzer=CCpp abrt-action-generate-backtrace +#EVENT=post-create + nice sosreport --tmp-dir "$DUMP_DIR" --batch \ + --only=anaconda --only=bootloader --only=devicemapper \ + --only=filesys --only=hardware --only=kernel --only=libraries \ + --only=memory --only=networking --only=nfsserver --only=pam \ + --only=process --only=rpm -k rpm.rpmva=off --only=ssh \ + --only=startup --only=yum --only=general --only=x11 \ + && { + rm sosreport*.md5 + mv sosreport*.tar.bz2 sosreport.tar.bz2 + mv sosreport*.tar.xz sosreport.tar.xz + true + } 2>/dev/null EVENT=report analyzer=Kerneloops abrt-action-kerneloops -EVENT=report_Bugzilla analyzer=CCpp abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf -EVENT=report_Logger analyzer=CCpp abrt-action-print -o /var/log/abrt.log EVENT=report_Bugzilla analyzer=Python abrt-action-bugzilla -c /etc/abrt/plugins/Bugzilla.conf EVENT=report_Logger analyzer=Python abrt-action-print -o /var/log/abrt.log diff --git a/src/daemon/comm_layer_inner.cpp b/src/daemon/comm_layer_inner.cpp new file mode 100644 index 00000000..9d5ddfc2 --- /dev/null +++ b/src/daemon/comm_layer_inner.cpp @@ -0,0 +1,90 @@ +/* + 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 <pthread.h> +#include <map> +#include "abrtlib.h" +#include "CommLayerServerDBus.h" +#include "comm_layer_inner.h" + +typedef std::map<uint64_t, std::string> map_uint_str_t; +static map_uint_str_t s_mapClientID; +static pthread_mutex_t s_map_mutex; +static bool s_map_mutex_inited; + +/* called via [p]error_msg() */ +static void warn_client(const char *msg) +{ + uint64_t key = uint64_t(pthread_self()); + + pthread_mutex_lock(&s_map_mutex); + map_uint_str_t::const_iterator ki = s_mapClientID.find(key); + const char* peer = (ki != s_mapClientID.end() ? ki->second.c_str() : NULL); + pthread_mutex_unlock(&s_map_mutex); + + if (peer) + { + send_dbus_sig_Warning(msg, peer); + } +} + +void init_daemon_logging(void) +{ + if (!s_map_mutex_inited) + { + s_map_mutex_inited = true; + pthread_mutex_init(&s_map_mutex, NULL); + g_custom_logger = &warn_client; + } +} + +void set_client_name(const char *name) +{ + uint64_t key = uint64_t(pthread_self()); + + pthread_mutex_lock(&s_map_mutex); + if (!name) { + s_mapClientID.erase(key); + } else { + s_mapClientID[key] = name; + } + pthread_mutex_unlock(&s_map_mutex); +} + +void update_client(const char *fmt, ...) +{ + uint64_t key = uint64_t(pthread_self()); + + pthread_mutex_lock(&s_map_mutex); + map_uint_str_t::const_iterator ki = s_mapClientID.find(key); + const char* peer = (ki != s_mapClientID.end() ? ki->second.c_str() : NULL); + pthread_mutex_unlock(&s_map_mutex); + + if (!peer) + return; + + va_list p; + va_start(p, fmt); + char *msg = xvasprintf(fmt, p); + va_end(p); + + VERB1 log("Update('%s'): %s", peer, msg); + send_dbus_sig_Update(msg, peer); + + free(msg); +} diff --git a/src/daemon/CommLayerServer.h b/src/daemon/comm_layer_inner.h index 5b7ecf57..48eb2010 100644 --- a/src/daemon/CommLayerServer.h +++ b/src/daemon/comm_layer_inner.h @@ -16,30 +16,39 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifndef COMMLAYERSERVER_H_ -#define COMMLAYERSERVER_H_ - -#include "abrtlib.h" -#include "abrt_crash_dump.h" - -class CCommLayerServer { - public: - int m_init_error; - - CCommLayerServer(); - virtual ~CCommLayerServer(); - - /* just stubs to be called when not implemented in specific comm layer */ - virtual void Crash(const char *package_name, - const char *crash_id, - const char *dir, - const char *uid_str - ) {} - virtual void JobDone(const char* peer) = 0; - virtual void QuotaExceed(const char* str) {} - - virtual void Update(const char* pMessage, const char* peer) {}; - virtual void Warning(const char* pMessage, const char* peer) {}; -}; +#ifndef COMMLAYERINNER_H_ +#define COMMLAYERINNER_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +void init_daemon_logging(void); + +/* + * Set client's name (dbus ID). NULL unsets it. + */ +void set_client_name(const char* name); + +/* + * Ask a client to warn the user about a non-fatal, but unexpected condition. + * In GUI, it will usually be presented as a popup message. + * Usually there is no need to call it directly, just use [p]error_msg(). + */ +//now static: +//void warn_client(const char *msg); +//use [p]error_msg[_and_die] instead, it sends the message as a warning to client +//as well as to the log. + +/* + * Logs a message to a client. + * In UI, it will usually appear as a new status line message in GUI, + * or as a new message line in CLI. + */ +void update_client(const char *fmt, ...); + +#ifdef __cplusplus +} +#endif #endif diff --git a/src/daemon/rpm.c b/src/daemon/rpm.c index a726d357..1295211e 100644 --- a/src/daemon/rpm.c +++ b/src/daemon/rpm.c @@ -16,7 +16,6 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include <glib.h> #include "abrtlib.h" #include "rpm.h" @@ -150,7 +149,6 @@ bool CheckHash(const char* pPackage, const char* pPath) goto error; rpmfi fi = rpmfiNew(ts, header, RPMTAG_BASENAMES, RPMFI_NOHEADER); - pgpHashAlgo hashAlgo; std::string headerHash; char computedHash[1024] = ""; @@ -158,8 +156,8 @@ bool CheckHash(const char* pPackage, const char* pPath) { if (strcmp(pPath, rpmfiFN(fi)) == 0) { - headerHash = rpmfiFDigestHex(fi, &hashAlgo); - rpmDoDigest(hashAlgo, pPath, 1, (unsigned char*) computedHash, NULL); + headerHash = rpmfiFDigestHex(fi, NULL); + rpmDoDigest(rpmfiDigestAlgo(fi), pPath, 1, (unsigned char*) computedHash, NULL); ret = (headerHash != "" && headerHash == computedHash); break; } @@ -172,27 +170,6 @@ error: } */ -char* rpm_get_description(const char* pkg) -{ - char *dsc = NULL; - const char *errmsg = NULL; - rpmts ts = rpmtsCreate(); - - rpmdbMatchIterator iter = rpmtsInitIterator(ts, RPMTAG_NAME, pkg, 0); - Header header = rpmdbNextIterator(iter); - if (!header) - goto error; - - dsc = headerFormat(header, "%{SUMMARY}\n\n%{DESCRIPTION}", &errmsg); - if (!dsc && errmsg) - error_msg("cannot get summary and description. reason: %s", errmsg); - -error: - rpmdbFreeIterator(iter); - rpmtsFree(ts); - return dsc; -} - char* rpm_get_component(const char* filename) { char *ret = NULL; diff --git a/src/daemon/rpm.h b/src/daemon/rpm.h index 12b11ca8..11f02809 100644 --- a/src/daemon/rpm.h +++ b/src/daemon/rpm.h @@ -58,12 +58,6 @@ void rpm_load_gpgkey(const char* filename); int rpm_chk_fingerprint(const char* pkg); /** - * Gets a package description. - * @param pkg A package name. - * @return A package description. - */ -char* rpm_get_description(const char* pkg); -/** * Gets a package name. This package contains particular * file. If the file doesn't belong to any package, empty string is * returned. |
