summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Applet/CCApplet.cpp13
-rw-r--r--src/Backtrace/main.c4
-rw-r--r--src/CLI/dbus.cpp6
-rw-r--r--src/CLI/dbus.h6
-rw-r--r--src/Daemon/CommLayerServerDBus.cpp14
-rw-r--r--src/Daemon/CrashWatcher.cpp12
-rw-r--r--src/Daemon/Daemon.cpp36
-rw-r--r--src/Daemon/MiddleWare.cpp45
-rw-r--r--src/Daemon/PluginManager.cpp282
-rw-r--r--src/Daemon/PluginManager.h31
-rw-r--r--src/Daemon/RPM.cpp4
-rw-r--r--src/Daemon/Settings.cpp7
-rw-r--r--src/Daemon/Settings.h1
-rwxr-xr-xsrc/Daemon/abrt-debuginfo-install6
-rw-r--r--src/Daemon/abrt.conf6
-rw-r--r--src/Daemon/abrt.conf.54
-rw-r--r--src/Gui/ABRTExceptions.py2
-rw-r--r--src/Gui/ABRTPlugin.py49
-rw-r--r--src/Gui/CCDBusBackend.py40
-rw-r--r--src/Gui/CCDumpList.py2
-rw-r--r--src/Gui/CCMainWindow.py61
-rw-r--r--src/Gui/CCReporterDialog.py4
-rw-r--r--src/Gui/CC_gui_functions.py20
-rw-r--r--src/Gui/ConfBackend.py171
-rw-r--r--src/Gui/PluginList.py22
-rw-r--r--src/Gui/PluginSettingsUI.py2
-rw-r--r--src/Gui/PluginsSettingsDialog.py122
-rw-r--r--src/Gui/SettingsDialog.py2
-rw-r--r--src/Gui/abrt_utils.py43
-rw-r--r--src/Hooks/Makefile.am8
-rw-r--r--src/Hooks/abrt-hook-ccpp.cpp (renamed from src/Hooks/CCpp.cpp)120
-rw-r--r--src/Hooks/abrt-hook-python.cpp96
-rw-r--r--src/Hooks/abrt_exception_handler.py.in2
-rw-r--r--src/Hooks/dumpoops.cpp1
-rw-r--r--src/Hooks/hooklib.cpp116
-rw-r--r--src/Hooks/hooklib.h21
36 files changed, 842 insertions, 539 deletions
diff --git a/src/Applet/CCApplet.cpp b/src/Applet/CCApplet.cpp
index 07e44d8..302fe0b 100644
--- a/src/Applet/CCApplet.cpp
+++ b/src/Applet/CCApplet.cpp
@@ -192,20 +192,21 @@ void CApplet::SetIconTooltip(const char *format, ...)
void CApplet::CrashNotify(const char *format, ...)
{
va_list args;
- char *buf;
- int n;
- GError *err = NULL;
va_start(args, format);
- buf = NULL;
- n = vasprintf(&buf, format, args);
+ char *buf = xvasprintf(format, args);
va_end(args);
notify_notification_update(m_pNotification, _("Warning"), buf, NULL);
+
+ GError *err = NULL;
if (gtk_status_icon_is_embedded(m_pStatusIcon))
notify_notification_show(m_pNotification, &err);
if (err != NULL)
- error_msg(err->message);
+ {
+ error_msg("%s", err->message);
+ g_error_free(err);
+ }
}
void CApplet::OnAppletActivate_CB(GtkStatusIcon *status_icon, gpointer user_data)
diff --git a/src/Backtrace/main.c b/src/Backtrace/main.c
index 7dfba43..5e69338 100644
--- a/src/Backtrace/main.c
+++ b/src/Backtrace/main.c
@@ -28,8 +28,8 @@
/* Too large files are trimmed. */
#define FILE_SIZE_LIMIT 20000000 /* ~ 20 MB */
-#define EX_PARSINGFAILED EX__MAX + 1
-#define EX_THREADDETECTIONFAILED EX__MAX + 2
+#define EX_PARSINGFAILED EX__MAX + 1 /* = 79 */
+#define EX_THREADDETECTIONFAILED EX__MAX + 2 /* = 80 */
const char *argp_program_version = "abrt-backtrace " VERSION;
const char *argp_program_bug_address = "<crash-catcher@lists.fedorahosted.org>";
diff --git a/src/CLI/dbus.cpp b/src/CLI/dbus.cpp
index b218679..0d03c4d 100644
--- a/src/CLI/dbus.cpp
+++ b/src/CLI/dbus.cpp
@@ -184,7 +184,8 @@ int32_t call_DeleteDebugDump(const char* uuid)
return result;
}
-vector_map_string_t call_GetPluginsInfo()
+#ifdef UNUSED
+map_map_string_t call_GetPluginsInfo()
{
DBusMessage *msg = new_call_msg(__func__ + 5);
DBusMessage *reply = send_get_reply_and_unref(msg);
@@ -192,7 +193,7 @@ vector_map_string_t call_GetPluginsInfo()
DBusMessageIter in_iter;
dbus_message_iter_init(reply, &in_iter);
- vector_map_string_t argout;
+ map_map_string_t argout;
int r = load_val(&in_iter, argout);
if (r != ABRT_DBUS_LAST_FIELD) /* more values present, or bad type */
error_msg_and_die("dbus call %s: return type mismatch", __func__ + 5);
@@ -200,6 +201,7 @@ vector_map_string_t call_GetPluginsInfo()
dbus_message_unref(reply);
return argout;
}
+#endif
void handle_dbus_err(bool error_flag, DBusError *err)
{
diff --git a/src/CLI/dbus.h b/src/CLI/dbus.h
index 3c157c0..c692e19 100644
--- a/src/CLI/dbus.h
+++ b/src/CLI/dbus.h
@@ -28,15 +28,17 @@ map_crash_report_t call_CreateReport(const char *uuid);
report_status_t call_Report(const map_crash_report_t& report);
int32_t call_DeleteDebugDump(const char* uuid);
+#ifdef UNUSED
/* Gets basic data about all installed plugins.
*/
-vector_map_string_t call_GetPluginsInfo();
+map_map_string_t call_GetPluginsInfo();
/** Gets default plugin settings.
* @param name
- * Corresponds to name obtained from call_GetPluginsInfo.
+ * Corresponds to name obtained from call_GetPluginsInfo.
*/
map_plugin_settings_t call_GetPluginSettings(const char *name);
+#endif
void handle_dbus_err(bool error_flag, DBusError *err);
diff --git a/src/Daemon/CommLayerServerDBus.cpp b/src/Daemon/CommLayerServerDBus.cpp
index 9222c59..db0d2f5 100644
--- a/src/Daemon/CommLayerServerDBus.cpp
+++ b/src/Daemon/CommLayerServerDBus.cpp
@@ -325,11 +325,9 @@ static int handle_DeleteDebugDump(DBusMessage* call, DBusMessage* reply)
static int handle_GetPluginsInfo(DBusMessage* call, DBusMessage* reply)
{
- vector_map_string_t plugins_info = g_pPluginManager->GetPluginsInfo();
-
DBusMessageIter out_iter;
dbus_message_iter_init_append(reply, &out_iter);
- store_val(&out_iter, plugins_info);
+ store_val(&out_iter, g_pPluginManager->GetPluginsInfo());
send_flush_and_unref(reply);
return 0;
@@ -348,9 +346,9 @@ static int handle_GetPluginSettings(DBusMessage* call, DBusMessage* reply)
return -1;
}
- 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 = g_pPluginManager->GetPluginSettings(PluginName, to_string(unix_uid).c_str());
+ //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 = g_pPluginManager->GetPluginSettings(PluginName); //, to_string(unix_uid).c_str());
DBusMessageIter out_iter;
dbus_message_iter_init_append(reply, &out_iter);
@@ -393,6 +391,7 @@ static int handle_SetPluginSettings(DBusMessage* call, DBusMessage* reply)
return 0;
}
+#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD
static int handle_RegisterPlugin(DBusMessage* call, DBusMessage* reply)
{
int r;
@@ -432,6 +431,7 @@ static int handle_UnRegisterPlugin(DBusMessage* call, DBusMessage* reply)
send_flush_and_unref(reply);
return 0;
}
+#endif
static int handle_GetSettings(DBusMessage* call, DBusMessage* reply)
{
@@ -496,10 +496,12 @@ static DBusHandlerResult message_received(DBusConnection* conn, DBusMessage* msg
r = handle_GetPluginSettings(msg, reply);
else if (strcmp(member, "SetPluginSettings") == 0)
r = handle_SetPluginSettings(msg, reply);
+#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD
else if (strcmp(member, "RegisterPlugin") == 0)
r = handle_RegisterPlugin(msg, reply);
else if (strcmp(member, "UnRegisterPlugin") == 0)
r = handle_UnRegisterPlugin(msg, reply);
+#endif
else if (strcmp(member, "GetSettings") == 0)
r = handle_GetSettings(msg, reply);
else if (strcmp(member, "SetSettings") == 0)
diff --git a/src/Daemon/CrashWatcher.cpp b/src/Daemon/CrashWatcher.cpp
index 88c058b..59f9e65 100644
--- a/src/Daemon/CrashWatcher.cpp
+++ b/src/Daemon/CrashWatcher.cpp
@@ -168,12 +168,11 @@ int CreateReportThread(const char* pUUID, const char* pUID, int force, const cha
thread_data->force = force;
thread_data->peer = xstrdup(pSender);
-//TODO: do we need this?
-//pthread_attr_t attr;
-//pthread_attr_init(&attr);
-//pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-
- int r = pthread_create(&thread_data->thread_id, NULL, create_report, thread_data);
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ int r = pthread_create(&thread_data->thread_id, &attr, create_report, thread_data);
+ pthread_attr_destroy(&attr);
if (r != 0)
{
free(thread_data->UUID);
@@ -187,7 +186,6 @@ int CreateReportThread(const char* pUUID, const char* pUID, int force, const cha
return r;
}
VERB3 log("Thread %llx created", (unsigned long long)thread_data->thread_id);
-//pthread_attr_destroy(&attr);
return r;
}
diff --git a/src/Daemon/Daemon.cpp b/src/Daemon/Daemon.cpp
index 1a6cadf..a2970af 100644
--- a/src/Daemon/Daemon.cpp
+++ b/src/Daemon/Daemon.cpp
@@ -65,7 +65,8 @@
* Returns report_status_t (map_vector_string_t) - the status of each call.
* 2nd parameter is the contents of user's abrt.conf.
* - DeleteDebugDump(UUID): delete it from DB and delete corresponding /var/cache/abrt/DIR
- * - GetPluginsInfo(): returns vector_map_string_t
+ * - GetPluginsInfo(): returns map_map_string_t
+ * map["plugin"] = { "Name": "plugin", "Enabled": "yes" ... }
* - GetPluginSettings(PluginName): returns map_plugin_settings_t (map_string_t)
* - SetPluginSettings(PluginName, map_plugin_settings_t): returns void
* - RegisterPlugin(PluginName): returns void
@@ -173,13 +174,6 @@ static int SetUpMW()
{
g_setBlackList.insert(*it_b);
}
- VERB1 log("Registering plugins");
- set_string_t::iterator it_p = g_settings_setEnabledPlugins.begin();
- for (; it_p != g_settings_setEnabledPlugins.end(); it_p++)
- {
- if (g_pPluginManager->RegisterPlugin(it_p->c_str()) != 0)
- return -1;
- }
VERB1 log("Adding actions or reporters");
vector_pair_string_string_t::iterator it_ar = g_settings_vectorActionsAndReporters.begin();
for (; it_ar != g_settings_vectorActionsAndReporters.end(); it_ar++)
@@ -210,10 +204,12 @@ static int SetUpCron()
int nM = -1;
int nS = -1;
+//TODO: rewrite using good old sscanf?
+
if (pos != std::string::npos)
{
- std::string sH = "";
- std::string sM = "";
+ std::string sH;
+ std::string sM;
sH = it_c->first.substr(0, pos);
nH = xatou(sH.c_str());
@@ -228,7 +224,7 @@ static int SetUpCron()
}
else
{
- std::string sS = "";
+ std::string sS;
sS = it_c->first;
nS = xatou(sS.c_str());
@@ -368,8 +364,8 @@ static int CreatePidFile()
if (fd >= 0)
{
/* write our pid to it */
- char buf[sizeof(int)*3 + 2];
- int len = sprintf(buf, "%u\n", (unsigned)getpid());
+ char buf[sizeof(long)*3 + 2];
+ int len = sprintf(buf, "%lu\n", (long)getpid());
write(fd, buf, len);
close(fd);
return 0;
@@ -637,7 +633,7 @@ static void start_syslog_logging()
logmode = LOGMODE_SYSLOG;
}
-static void ensure_writable_dir(const char *dir, mode_t mode, const char *group)
+static void ensure_writable_dir(const char *dir, mode_t mode, const char *user)
{
struct stat sb;
@@ -646,12 +642,12 @@ static void ensure_writable_dir(const char *dir, mode_t mode, const char *group)
if (stat(dir, &sb) != 0 || !S_ISDIR(sb.st_mode))
error_msg_and_die("'%s' is not a directory", dir);
- struct group *gr = getgrnam(group);
- if (!gr)
- perror_msg_and_die("Can't find group '%s'", group);
+ struct passwd *pw = getpwnam(user);
+ if (!pw)
+ perror_msg_and_die("Can't find user '%s'", user);
- if ((sb.st_uid != 0 || sb.st_gid != gr->gr_gid) && chown(dir, 0, gr->gr_gid) != 0)
- perror_msg_and_die("Can't set owner 0:%u on '%s'", (unsigned int)gr->gr_gid, dir);
+ if ((sb.st_uid != pw->pw_uid || sb.st_gid != pw->pw_gid) && chown(dir, pw->pw_uid, pw->pw_gid) != 0)
+ perror_msg_and_die("Can't set owner %u:%u on '%s'", (unsigned int)pw->pw_uid, (unsigned int)pw->pw_gid, dir);
if ((sb.st_mode & 07777) != mode && chmod(dir, mode) != 0)
perror_msg_and_die("Can't set mode %o on '%s'", mode, dir);
}
@@ -662,7 +658,7 @@ static void sanitize_dump_dir_rights()
* us with thousands of bogus or malicious dumps */
/* 07000 bits are setuid, setgit, and sticky, and they must be unset */
/* 00777 bits are usual "rwxrwxrwx" access rights */
- ensure_writable_dir(DEBUG_DUMPS_DIR, 0775, "abrt");
+ ensure_writable_dir(DEBUG_DUMPS_DIR, 0755, "abrt");
/* debuginfo cache */
ensure_writable_dir(DEBUG_DUMPS_DIR"-di", 0755, "root");
/* temp dir */
diff --git a/src/Daemon/MiddleWare.cpp b/src/Daemon/MiddleWare.cpp
index 25fe253..70527eb 100644
--- a/src/Daemon/MiddleWare.cpp
+++ b/src/Daemon/MiddleWare.cpp
@@ -204,7 +204,11 @@ static void DebugDumpToCrashReport(const char *pDebugDumpDir, map_crash_report_t
static std::string GetLocalUUID(const char *pAnalyzer, const char *pDebugDumpDir)
{
CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer);
- return analyzer->GetLocalUUID(pDebugDumpDir);
+ if (analyzer)
+ {
+ return analyzer->GetLocalUUID(pDebugDumpDir);
+ }
+ throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer);
}
/**
@@ -217,7 +221,11 @@ static std::string GetGlobalUUID(const char *pAnalyzer,
const char *pDebugDumpDir)
{
CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer);
- return analyzer->GetGlobalUUID(pDebugDumpDir);
+ if (analyzer)
+ {
+ return analyzer->GetGlobalUUID(pDebugDumpDir);
+ }
+ throw CABRTException(EXCEP_PLUGIN, "Error running '%s'", pAnalyzer);
}
/**
@@ -232,7 +240,11 @@ static void CreateReport(const char *pAnalyzer,
int force)
{
CAnalyzer* analyzer = g_pPluginManager->GetAnalyzer(pAnalyzer);
- analyzer->CreateReport(pDebugDumpDir, force);
+ if (analyzer)
+ {
+ analyzer->CreateReport(pDebugDumpDir, force);
+ }
+ /* else: GetAnalyzer() already complained, no need to handle it here */
}
mw_result_t CreateCrashReport(const char *pUUID,
@@ -320,9 +332,14 @@ void RunAction(const char *pActionDir,
const char *pPluginName,
const char *pPluginArgs)
{
+ CAction* action = g_pPluginManager->GetAction(pPluginName);
+ if (!action)
+ {
+ /* GetAction() already complained */
+ return;
+ }
try
{
- CAction* action = g_pPluginManager->GetAction(pPluginName);
action->Run(pActionDir, pPluginArgs);
}
catch (CABRTException& e)
@@ -500,7 +517,9 @@ report_status_t Report(const map_crash_report_t& pCrashReport,
#endif
ret[plugin_name].push_back("1"); // REPORT_STATUS_IDX_FLAG
ret[plugin_name].push_back(res); // REPORT_STATUS_IDX_MSG
- message += res + "\n";
+ if (message != "")
+ message += "; ";
+ message += res;
}
}
catch (CABRTException& e)
@@ -531,6 +550,8 @@ report_status_t Report(const map_crash_report_t& pCrashReport,
static bool IsDebugDumpSaved(const char *pUID,
const char *pDebugDumpDir)
{
+ /* TODO: use database query instead of dumping all rows and searching in them */
+
CDatabase* database = g_pPluginManager->GetDatabase(g_settings_sDatabase.c_str());
database->Connect();
vector_database_rows_t rows = database->GetUIDData(pUID);
@@ -770,13 +791,17 @@ static void RunAnalyzerActions(const char *pAnalyzer, const char *pDebugDumpDir)
for (; it_a != analyzer->second.end(); it_a++)
{
const char *plugin_name = it_a->first.c_str();
+ CAction* action = g_pPluginManager->GetAction(plugin_name, /*silent:*/ true);
+ if (!action)
+ {
+ /* GetAction() already complained if no such plugin.
+ * If plugin exists but isn't an Action, it's not an error.
+ */
+ continue;
+ }
try
{
- if (g_pPluginManager->GetPluginType(plugin_name) == ACTION)
- {
- CAction* action = g_pPluginManager->GetAction(plugin_name);
- action->Run(pDebugDumpDir, it_a->second.c_str());
- }
+ action->Run(pDebugDumpDir, it_a->second.c_str());
}
catch (CABRTException& e)
{
diff --git a/src/Daemon/PluginManager.cpp b/src/Daemon/PluginManager.cpp
index 663228b..c552880 100644
--- a/src/Daemon/PluginManager.cpp
+++ b/src/Daemon/PluginManager.cpp
@@ -27,6 +27,8 @@
#include "Polkit.h"
#include "PluginManager.h"
+using namespace std;
+
/**
* Text representation of plugin types.
*/
@@ -40,12 +42,12 @@ static const char *const plugin_type_str[] = {
bool LoadPluginSettings(const char *pPath, map_plugin_settings_t& pSettings)
{
- std::ifstream fIn;
+ ifstream fIn;
fIn.open(pPath);
if (!fIn.is_open())
return false;
- std::string line;
+ string line;
while (!fIn.eof())
{
getline(fIn, line);
@@ -54,8 +56,8 @@ bool LoadPluginSettings(const char *pPath, map_plugin_settings_t& pSettings)
bool is_value = false;
bool valid = false;
bool in_quote = false;
- std::string key;
- std::string value;
+ string key;
+ string value;
for (ii = 0; ii < line.length(); ii++)
{
if (line[ii] == '"')
@@ -138,7 +140,9 @@ void CPluginManager::LoadPlugins()
if (!ext || strcmp(ext + 1, PLUGINS_LIB_EXTENSION) != 0)
continue;
*ext = '\0';
- LoadPlugin(dent->d_name + sizeof(PLUGINS_LIB_PREFIX)-1);
+ 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);
}
@@ -153,16 +157,51 @@ void CPluginManager::UnLoadPlugins()
}
}
-void CPluginManager::LoadPlugin(const char *pName)
+CPlugin* CPluginManager::LoadPlugin(const char *pName, bool enabled_only)
{
- if (m_mapLoadedModules.find(pName) != m_mapLoadedModules.end())
+ map_string_t plugin_info;
+
+ plugin_info["Name"] = pName;
+
+ map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
+ if (it_plugin != m_mapPlugins.end())
{
- return;
+ return it_plugin->second; /* ok */
}
- std::string libPath = ssprintf(PLUGINS_LIB_DIR"/"PLUGINS_LIB_PREFIX"%s."PLUGINS_LIB_EXTENSION, pName);
- CLoadedModule* module = new CLoadedModule(libPath.c_str());
+ 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;
+ VERB3 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;
+ m_map_plugin_info[pName] = plugin_info;
+ 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);
+ CLoadedModule* module = new CLoadedModule(libPath.c_str());
if (module->GetMagicNumber() != PLUGINS_MAGIC_NUMBER
|| module->GetType() < 0
|| module->GetType() > MAX_PLUGIN_TYPE
@@ -172,95 +211,74 @@ void CPluginManager::LoadPlugin(const char *pName)
module->GetMagicNumber(), PLUGINS_MAGIC_NUMBER,
module->GetType(), MAX_PLUGIN_TYPE);
delete module;
- return;
+ return NULL; /* error */
}
+ VERB3 log("Loaded plugin %s v.%s", pName, module->GetVersion());
- log("Plugin %s (%s) succesfully loaded", pName, module->GetVersion());
- m_mapLoadedModules[pName] = module;
-}
-
-void CPluginManager::UnLoadPlugin(const char *pName)
-{
- map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName);
- if (it_module != m_mapLoadedModules.end())
- {
- UnRegisterPlugin(pName);
- delete it_module->second;
- m_mapLoadedModules.erase(it_module);
- log("Plugin %s successfully unloaded", pName);
- }
-}
-
-int CPluginManager::RegisterPlugin(const char *pName)
-{
- map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName);
- if (it_module == m_mapLoadedModules.end())
- {
- error_msg("Can't initialize plugin %s: no such plugin installed", pName);
- return -1; /* failure */
- }
- if (m_mapPlugins.find(pName) != m_mapPlugins.end())
- {
- return 0; /* already registered, success */
- }
-
- /* Loaded, but not registered yet */
- CPlugin* plugin = it_module->second->PluginNew();
- map_plugin_settings_t pluginSettings;
-
- const char *conf_name = pName;
- if (strncmp(pName, "Kerneloops", sizeof("Kerneloops")-1) == 0) {
- /* Kerneloops{,Scanner,Reporter} share the same .conf file */
- conf_name = "Kerneloops";
- }
- LoadPluginSettings(ssprintf(PLUGINS_CONF_DIR"/%s."PLUGINS_CONF_EXTENSION, conf_name).c_str(), pluginSettings);
- VERB3 log("Loaded %s.conf", conf_name);
+ CPlugin* plugin = NULL;
try
{
+ plugin = module->PluginNew();
plugin->Init();
plugin->SetSettings(pluginSettings);
}
catch (CABRTException& e)
{
- error_msg("Can't initialize plugin %s(%s): %s",
+ error_msg("Can't initialize plugin %s: %s",
pName,
- plugin_type_str[it_module->second->GetType()],
e.what()
);
- UnLoadPlugin(pName);
- return -1; /* failure */
+ delete plugin;
+ delete module;
+ return NULL; /* error */
}
- m_mapPlugins[pName] = plugin;
- log("Registered plugin %s(%s)", pName, plugin_type_str[it_module->second->GetType()]);
- return 0; /* success */
-}
-void CPluginManager::RegisterPluginDBUS(const char *pName, const char *pDBUSSender)
-{
- int polkit_result = polkit_check_authorization(pDBUSSender,
- "org.fedoraproject.abrt.change-daemon-settings");
- if (polkit_result == PolkitYes)
- {
- RegisterPlugin(pName);
- } else
- {
- log("User %s not authorized, returned %d", pDBUSSender, polkit_result);
- }
+ 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_map_plugin_info[pName] = plugin_info;
+ m_mapLoadedModules[pName] = module;
+ m_mapPlugins[pName] = plugin;
+ log("Registered %s plugin '%s'", plugin_type_str[module->GetType()], pName);
+ return plugin; /* ok */
}
-void CPluginManager::UnRegisterPlugin(const char *pName)
+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())
+ if (it_plugin != m_mapPlugins.end()) /* always true */
{
it_plugin->second->DeInit();
delete it_plugin->second;
m_mapPlugins.erase(it_plugin);
- log("UnRegistered plugin %s(%s)", pName, plugin_type_str[it_module->second->GetType()]);
}
+ log("UnRegistered %s plugin %s", plugin_type_str[it_module->second->GetType()], pName);
+ m_mapLoadedModules.erase(it_module);
+ delete it_module->second;
+ }
+}
+
+#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD
+void CPluginManager::RegisterPluginDBUS(const char *pName, const char *pDBUSSender)
+{
+ int polkit_result = polkit_check_authorization(pDBUSSender,
+ "org.fedoraproject.abrt.change-daemon-settings");
+ if (polkit_result == PolkitYes)
+ {
+//TODO: report success/failure
+ LoadPlugin(pName);
+ } else
+ {
+ log("User %s not authorized, returned %d", pDBUSSender, polkit_result);
}
}
@@ -270,60 +288,67 @@ void CPluginManager::UnRegisterPluginDBUS(const char *pName, const char *pDBUSSe
"org.fedoraproject.abrt.change-daemon-settings");
if (polkit_result == PolkitYes)
{
- UnRegisterPlugin(pName);
+ UnLoadPlugin(pName);
} else
{
log("user %s not authorized, returned %d", pDBUSSender, polkit_result);
}
}
-
+#endif
CAnalyzer* CPluginManager::GetAnalyzer(const char *pName)
{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin == m_mapPlugins.end())
+ CPlugin* plugin = LoadPlugin(pName);
+ if (!plugin)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName);
+ error_msg("Plugin '%s' is not registered", pName);
+ return NULL;
}
if (m_mapLoadedModules[pName]->GetType() != ANALYZER)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not an analyzer plugin", pName);
+ error_msg("Plugin '%s' is not an analyzer plugin", pName);
+ return NULL;
}
- return (CAnalyzer*)(it_plugin->second);
+ return (CAnalyzer*)plugin;
}
CReporter* CPluginManager::GetReporter(const char *pName)
{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin == m_mapPlugins.end())
+ CPlugin* plugin = LoadPlugin(pName);
+ if (!plugin)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName);
+ error_msg("Plugin '%s' is not registered", pName);
+ return NULL;
}
if (m_mapLoadedModules[pName]->GetType() != REPORTER)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not a reporter plugin", pName);
+ error_msg("Plugin '%s' is not a reporter plugin", pName);
+ return NULL;
}
- return (CReporter*)(it_plugin->second);
+ return (CReporter*)plugin;
}
-CAction* CPluginManager::GetAction(const char *pName)
+CAction* CPluginManager::GetAction(const char *pName, bool silent)
{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin == m_mapPlugins.end())
+ CPlugin* plugin = LoadPlugin(pName);
+ if (!plugin)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName);
+ error_msg("Plugin '%s' is not registered", pName);
+ return NULL;
}
if (m_mapLoadedModules[pName]->GetType() != ACTION)
{
- throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not an action plugin", pName);
+ if (!silent)
+ error_msg("Plugin '%s' is not an action plugin", pName);
+ return NULL;
}
- return (CAction*)(it_plugin->second);
+ return (CAction*)plugin;
}
CDatabase* CPluginManager::GetDatabase(const char *pName)
{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin == m_mapPlugins.end())
+ CPlugin* plugin = LoadPlugin(pName);
+ if (!plugin)
{
throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName);
}
@@ -331,39 +356,18 @@ CDatabase* CPluginManager::GetDatabase(const char *pName)
{
throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not a database plugin", pName);
}
- return (CDatabase*)(it_plugin->second);
+ return (CDatabase*)plugin;
}
plugin_type_t CPluginManager::GetPluginType(const char *pName)
{
- map_plugin_t::iterator it_plugin = m_mapPlugins.find(pName);
- if (it_plugin == m_mapPlugins.end())
+ CPlugin* plugin = LoadPlugin(pName);
+ if (!plugin)
{
throw CABRTException(EXCEP_PLUGIN, "Plugin '%s' is not registered", pName);
}
- return m_mapLoadedModules[pName]->GetType();
-}
-
-vector_map_string_t CPluginManager::GetPluginsInfo()
-{
- vector_map_string_t ret;
- map_loaded_module_t::iterator it_module = m_mapLoadedModules.begin();
- for (; it_module != m_mapLoadedModules.end(); it_module++)
- {
- map_string_t plugin_info;
-
- plugin_info["Enabled"] = (m_mapPlugins.find(it_module->second->GetName()) != m_mapPlugins.end()) ?
- "yes" : "no";
- plugin_info["Type"] = plugin_type_str[it_module->second->GetType()];
- plugin_info["Name"] = it_module->second->GetName();
- plugin_info["Version"] = it_module->second->GetVersion();
- plugin_info["Description"] = it_module->second->GetDescription();
- plugin_info["Email"] = it_module->second->GetEmail();
- plugin_info["WWW"] = it_module->second->GetWWW();
- plugin_info["GTKBuilder"] = it_module->second->GetGTKBuilder();
- ret.push_back(plugin_info);
- }
- return ret;
+ map_loaded_module_t::iterator it_module = m_mapLoadedModules.find(pName);
+ return it_module->second->GetType();
}
void CPluginManager::SetPluginSettings(const char *pName,
@@ -388,14 +392,14 @@ void CPluginManager::SetPluginSettings(const char *pName,
return;
}
- std::string home = get_home_dir(xatoi_u(pUID.c_str()));
+ string home = get_home_dir(xatoi_u(pUID.c_str()));
if (home == "")
{
return;
}
- std::string confDir = home + "/.abrt";
- std::string confPath = confDir + "/" + pName + "."PLUGINS_CONF_EXTENSION;
+ string confDir = home + "/.abrt";
+ string confPath = confDir + "/" + pName + "."PLUGINS_CONF_EXTENSION;
uid_t uid = xatoi_u(pUID.c_str());
struct passwd* pw = getpwuid(uid);
gid_t gid = pw ? pw->pw_gid : uid;
@@ -415,7 +419,7 @@ void CPluginManager::SetPluginSettings(const char *pName,
}
if (chown(confDir.c_str(), uid, gid) == -1)
{
- perror_msg("Can't change '%s' ownership to %u:%u", confPath.c_str(), (int)uid, (int)gid);
+ perror_msg("Can't change '%s' ownership to %lu:%lu", confPath.c_str(), (long)uid, (long)gid);
return;
}
}
@@ -433,40 +437,38 @@ void CPluginManager::SetPluginSettings(const char *pName,
SavePluginSettings(confPath, pSettings);
if (chown(confPath.c_str(), uid, gid) == -1)
{
- perror_msg("Can't change '%s' ownership to %u:%u", confPath.c_str(), (int)uid, (int)gid);
+ perror_msg("Can't change '%s' ownership to %lu:%lu", confPath.c_str(), (long)uid, (long)gid);
return;
}
*/
#endif
}
-map_plugin_settings_t CPluginManager::GetPluginSettings(const char *pName,
- const char *pUID)
+map_plugin_settings_t CPluginManager::GetPluginSettings(const char *pName)
{
map_plugin_settings_t ret;
+
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())
{
+ VERB3 log("Returning settings for loaded plugin %s", pName);
ret = it_plugin->second->GetSettings();
- /** we don't want to load it from daemon if it's running under root
- but wi might get back to this once we make the daemon to not run
- with root privileges
- */
- /*
- if (it_module->second->GetType() == REPORTER)
- {
- std::string home = get_home_dir(xatoi_u(pUID.c_str()));
- if (home != "")
- {
- LoadPluginSettings(home + "/.abrt/" + pName + "."PLUGINS_CONF_EXTENSION, ret);
- }
- }
- */
return ret;
}
}
+ /* else: module is not loaded */
+ map_map_string_t::iterator it_settings = m_map_plugin_settings.find(pName);
+ if (it_settings != m_map_plugin_settings.end())
+ {
+ /* but it exists, its settings are available nevertheless */
+ VERB3 log("Returning settings for non-loaded plugin %s", pName);
+ ret = it_settings->second;
+ return ret;
+ }
+
+ VERB3 log("Request for settings of unknown plugin %s, returning null result", pName);
return ret;
}
diff --git a/src/Daemon/PluginManager.h b/src/Daemon/PluginManager.h
index 2d649c5..22cc387 100644
--- a/src/Daemon/PluginManager.h
+++ b/src/Daemon/PluginManager.h
@@ -50,6 +50,11 @@ class CPluginManager
* 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_info;
+ map_map_string_t m_map_plugin_settings;
public:
/**
@@ -74,28 +79,17 @@ class CPluginManager
* A method, which loads particular plugin.
* @param pName A plugin name.
*/
- void LoadPlugin(const char *pName);
+ 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);
+#ifdef PLUGIN_DYNAMIC_LOAD_UNLOAD
/**
* A method, which registers particular plugin.
* @param pName A plugin name.
*/
- int RegisterPlugin(const char *pName);
- /**
- * A method, which unregister particular plugin.
- * @param pName A plugin name.
- */
- void UnRegisterPlugin(const char *pName);
- /**
- * A method, which registers particular plugin,
- * called via DBUS
- * @param pName A plugin name.
- * @param pDBUSSender DBUS user identification
- */
void RegisterPluginDBUS(const char *pName, const char *pDBUSSender);
/**
* A method, which unregister particular plugin,
@@ -104,6 +98,7 @@ class CPluginManager
* @param pDBUSSender DBUS user identification
*/
void UnRegisterPluginDBUS(const char *pName, const char *pDBUSSender);
+#endif
/**
* A method, which returns instance of particular analyzer plugin.
* @param pName A plugin name.
@@ -121,7 +116,7 @@ class CPluginManager
* @param pName A plugin name.
* @return An action plugin.
*/
- CAction* GetAction(const char *pName);
+ CAction* GetAction(const char *pName, bool silent = false);
/**
* A method, which returns instance of particular database plugin.
* @param pName A plugin name.
@@ -140,7 +135,7 @@ class CPluginManager
* Then user can fill all needed informations like URLs etc.
* @return A vector of maps <key, value>
*/
- vector_map_string_t GetPluginsInfo();
+ const map_map_string_t& GetPluginsInfo() { return m_map_plugin_info; }
/**
* A method, which sets up a plugin. The settings are also saved in home
* directory of an user.
@@ -154,11 +149,9 @@ class CPluginManager
/**
* A method, which returns plugin's settings according to user.
* @param pName A plugin name.
- * @param pUID An uid of user.
- * @return Plugin's settings accorting to user.
+ * @return Plugin's settings.
*/
- map_plugin_settings_t GetPluginSettings(const char *pName,
- const char *pUID);
+ map_plugin_settings_t GetPluginSettings(const char *pName);
};
/**
diff --git a/src/Daemon/RPM.cpp b/src/Daemon/RPM.cpp
index 6f05c0b..6cc0ba6 100644
--- a/src/Daemon/RPM.cpp
+++ b/src/Daemon/RPM.cpp
@@ -4,8 +4,8 @@
CRPM::CRPM()
{
- char *argv[] = { (char*)"" };
- m_poptContext = rpmcliInit(0, argv, NULL);
+ static const char *const argv[] = { "", NULL };
+ m_poptContext = rpmcliInit(1, (char**)argv, NULL);
}
CRPM::~CRPM()
diff --git a/src/Daemon/Settings.cpp b/src/Daemon/Settings.cpp
index d89bebf..48658e2 100644
--- a/src/Daemon/Settings.cpp
+++ b/src/Daemon/Settings.cpp
@@ -37,7 +37,6 @@ bool g_settings_bOpenGPGCheck = false;
/* one line: "OpenGPGPublicKeys = value1,value2" */
set_string_t g_settings_setOpenGPGPublicKeys;
set_string_t g_settings_mapBlackList;
-set_string_t g_settings_setEnabledPlugins;
std::string g_settings_sDatabase;
unsigned int g_settings_nMaxCrashReportsSize = 1000;
/* one line: "ActionsAndReporters = aa_first,bb_first(bb_second),cc_first" */
@@ -168,11 +167,6 @@ static void ParseCommon()
{
g_settings_sDatabase = it->second;
}
- it = s_mapSectionCommon.find("EnabledPlugins");
- if (it != end)
- {
- g_settings_setEnabledPlugins = ParseList(it->second.c_str());
- }
it = s_mapSectionCommon.find("MaxCrashReportsSize");
if (it != end)
{
@@ -434,7 +428,6 @@ void SaveSettings()
SaveBool("OpenGPGCheck", g_settings_bOpenGPGCheck, fOut);
SaveSetString("OpenGPGPublicKeys", g_settings_setOpenGPGPublicKeys, fOut);
SaveSetString("BlackList", g_settings_mapBlackList, fOut);
- SaveSetString("EnabledPlugins", g_settings_setEnabledPlugins, fOut);
fprintf(fOut, "Database = %s\n", g_settings_sDatabase.c_str());
fprintf(fOut, "MaxCrashReportsSize = %u\n", g_settings_nMaxCrashReportsSize);
SaveVectorPairStrings("ActionsAndReporters", g_settings_vectorActionsAndReporters, fOut);
diff --git a/src/Daemon/Settings.h b/src/Daemon/Settings.h
index 9ee9370..3fdb8b9 100644
--- a/src/Daemon/Settings.h
+++ b/src/Daemon/Settings.h
@@ -9,7 +9,6 @@ typedef map_map_string_t map_abrt_settings_t;
extern set_string_t g_settings_setOpenGPGPublicKeys;
extern set_string_t g_settings_mapBlackList;
-extern set_string_t g_settings_setEnabledPlugins;
extern unsigned int g_settings_nMaxCrashReportsSize;
extern bool g_settings_bOpenGPGCheck;
extern std::string g_settings_sDatabase;
diff --git a/src/Daemon/abrt-debuginfo-install b/src/Daemon/abrt-debuginfo-install
index cfae49a..35f4d6a 100755
--- a/src/Daemon/abrt-debuginfo-install
+++ b/src/Daemon/abrt-debuginfo-install
@@ -145,9 +145,11 @@ print_package_names() {
fi
# when we look for debuginfo we need only -debuginfo* repos, so we can disable the rest and thus make it faster
# also we want only fedora repositories, because abrt won't work for other packages anyway
- local cmd="yum $yumopts --disablerepo=* --enablerepo=fedora-debuginfo* --enablerepo=updates-debuginfo* --quiet provides $missing_debuginfo_files"
+ local cmd="yum $yumopts '--disablerepo=*' '--enablerepo=fedora-debuginfo*' '--enablerepo=updates-debuginfo*' --quiet provides $missing_debuginfo_files"
echo "$cmd" >"yum_provides.$1.OUT"
- local yum_provides_OUT="`$cmd 2>&1`"
+ # eval is needed to strip away ''s; cant remove them above and just use
+ # $cmd, that would perform globbing on '*'
+ local yum_provides_OUT="`eval $cmd 2>&1`"
local err=$?
printf "%s\nyum exitcode:%s\n" "$yum_provides_OUT" $err >>"yum_provides.$1.OUT"
test $err = 0 || error_msg_and_die "yum provides... exited with $err:
diff --git a/src/Daemon/abrt.conf b/src/Daemon/abrt.conf
index 276bf25..acf8566 100644
--- a/src/Daemon/abrt.conf
+++ b/src/Daemon/abrt.conf
@@ -9,11 +9,7 @@ OpenGPGCheck = no
OpenGPGPublicKeys = /etc/pki/rpm-gpg/RPM-GPG-KEY-fedora
# Blacklisted packages
BlackList = nspluginwrapper
-# Enabled plugins.
-# You can disable handling e.g. Python crashes by not listing Python here.
-# There has to be exactly one database plugin enabled.
-EnabledPlugins = SQLite3, CCpp, Logger, Kerneloops, KerneloopsScanner, KerneloopsReporter, Bugzilla, Python, RunApp
-# Database
+# Which database plugin to use
Database = SQLite3
# Max size for crash storage [MiB]
MaxCrashReportsSize = 1000
diff --git a/src/Daemon/abrt.conf.5 b/src/Daemon/abrt.conf.5
index 3b172bc..7114f5c 100644
--- a/src/Daemon/abrt.conf.5
+++ b/src/Daemon/abrt.conf.5
@@ -30,10 +30,6 @@ to report them if "EnableOpenGPG = yes".
.I abrt
will ignore packages in this list and will not handle their crashes.
.TP
-.B EnabledPlugins = \fIplugin\fP, \fIplugin\fP ...
-.I abrt
-will only load plugins in this list.
-.TP
.B Database = \fIdatabasePlugin\fP
This specifies which database plugin
.I abrt
diff --git a/src/Gui/ABRTExceptions.py b/src/Gui/ABRTExceptions.py
index c4d6b59..c857f71 100644
--- a/src/Gui/ABRTExceptions.py
+++ b/src/Gui/ABRTExceptions.py
@@ -1,4 +1,4 @@
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
class IsRunning(Exception):
def __init__(self):
diff --git a/src/Gui/ABRTPlugin.py b/src/Gui/ABRTPlugin.py
index ea90b87..320c81c 100644
--- a/src/Gui/ABRTPlugin.py
+++ b/src/Gui/ABRTPlugin.py
@@ -10,49 +10,51 @@ Type
Email
Description
"""
-from abrt_utils import _
-from ConfBackend import ConfBackendGnomeKeyring, ConfBackendInitError
+from abrt_utils import _, log, log1, log2
+from ConfBackend import getCurrentConfBackend, ConfBackendInitError
class PluginSettings(dict):
def __init__(self):
dict.__init__(self)
- self.conf = None
+ self.client_side_conf = None
try:
- self.conf = ConfBackendGnomeKeyring()
+ self.client_side_conf = getCurrentConfBackend()
except ConfBackendInitError, e:
print e
pass
def check(self):
+ # if present, these should be non-empty
for key in ["Password", "Login"]:
if key in self.keys():
- # some of the required keys is missing
if not self[key]:
+ # some of the required keys are missing
return False
# settings are OK
return True
- def load(self, name, default_settings):
+ def load_daemon_settings(self, name, daemon_settings):
# load settings from daemon
- for key in default_settings.keys():
- self[str(key)] = str(default_settings[key])
+ for key in daemon_settings.keys():
+ self[str(key)] = str(daemon_settings[key])
- if self.conf:
- settings = self.conf.load(name)
- # overwrite defaluts with user setting
+ if self.client_side_conf:
+ settings = self.client_side_conf.load(name)
+ # overwrite daemon data with user setting
for key in settings.keys():
- # only rewrite keys needed by the plugin
- # e.g we don't want a pass field for logger
- if key in default_settings.keys():
+ # only rewrite keys which exist in plugin's keys.
+ # e.g. we don't want a password field for logger plugin
+ if key in daemon_settings.keys():
self[str(key)] = str(settings[key])
- def save(self, name):
- if self.conf:
- self.conf.save(name, self)
+ def save_on_client_side(self, name):
+ if self.client_side_conf:
+ self.client_side_conf.save(name, self)
class PluginInfo():
"""Class to represent common plugin info"""
- types = {"Analyzer":_("Analyzer plugins"),
+ types = {"":_("Not loaded plugins"),
+ "Analyzer":_("Analyzer plugins"),
"Action":_("Action plugins"),
"Reporter":_("Reporter plugins"),
"Database":_("Database plugins")}
@@ -61,7 +63,6 @@ class PluginInfo():
"Type", "Email", "Description"]
def __init__(self):
- #print "Init PluginInfo"
self.WWW = None
self.Name = None
self.Enabled = None
@@ -90,11 +91,11 @@ class PluginInfo():
def __getitem__(self, item):
return self.__dict__[item]
- def load_settings(self, default_settings):
+ def load_daemon_settings(self, daemon_settings):
if self.Name:
- self.Settings.load(self.Name, default_settings)
+ self.Settings.load_daemon_settings(self.Name, daemon_settings)
else:
- print _("Plugin name is not set, can't load its settings")
+ log("Plugin name is not set, can't load its settings")
- def save_settings(self):
- self.Settings.save(str(self.Name))
+ def save_settings_on_client_side(self):
+ self.Settings.save_on_client_side(str(self.Name))
diff --git a/src/Gui/CCDBusBackend.py b/src/Gui/CCDBusBackend.py
index 85987e8..f4ef104 100644
--- a/src/Gui/CCDBusBackend.py
+++ b/src/Gui/CCDBusBackend.py
@@ -6,7 +6,7 @@ from dbus.mainloop.glib import DBusGMainLoop
import gtk
from dbus.exceptions import *
import ABRTExceptions
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
CC_NAME = 'com.redhat.abrt'
CC_IFACE = 'com.redhat.abrt'
@@ -40,7 +40,7 @@ class DBusManager(gobject.GObject):
if session:
try:
- app_proxy = session.get_object(APP_NAME,APP_PATH)
+ app_proxy = session.get_object(APP_NAME, APP_PATH)
app_iface = dbus.Interface(app_proxy, dbus_interface=APP_IFACE)
# app is running, so make it show it self
app_iface.show()
@@ -111,13 +111,13 @@ class DBusManager(gobject.GObject):
# def disconnected(self, *args):
# print "disconnect"
- def error_handler_cb(self,error):
- self.emit("abrt-error",error)
+ def error_handler_cb(self, error):
+ self.emit("abrt-error", error)
- def warning_handler_cb(self,arg):
- self.emit("warning",arg)
+ def warning_handler_cb(self, arg):
+ self.emit("warning", arg)
- def error_handler(self,arg):
+ def error_handler(self, arg):
# used to silently ingore dbus timeouts
pass
@@ -134,11 +134,11 @@ class DBusManager(gobject.GObject):
self.emit("crash")
def update_cb(self, message, job_id=0):
- print "Update >>%s<<" % message
+ log1("Update:%s", message)
self.emit("update", message)
def warning_cb(self, message, job_id=0):
- print "Warning >>%s<<" % message
+ log1("Warning:%s", message)
self.emit("warning", message)
def owner_changed_cb(self,name, old_owner, new_owner):
@@ -151,7 +151,7 @@ class DBusManager(gobject.GObject):
def jobdone_cb(self, dest, uuid):
# TODO: check that it is indeed OUR job:
# remember uuid in getReport and compare here
- print "Our job for UUID %s is done." % uuid
+ log1("Our job for UUID %s is done", uuid)
dump = self.daemon().CreateReport(uuid)
if dump:
self.emit("analyze-complete", dump)
@@ -167,7 +167,10 @@ class DBusManager(gobject.GObject):
def Report(self, report, reporters_settings = None):
# map < Plguin_name vec <status, message> >
- self.daemon().Report(report, reporters_settings, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60)
+ if reporters_settings:
+ self.daemon().Report(report, reporters_settings, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60)
+ else:
+ self.daemon().Report(report, reply_handler=self.report_done, error_handler=self.error_handler_cb, timeout=60)
def DeleteDebugDump(self,UUID):
return self.daemon().DeleteDebugDump(UUID)
@@ -188,15 +191,14 @@ class DBusManager(gobject.GObject):
def getPluginSettings(self, plugin_name):
settings = self.daemon().GetPluginSettings(plugin_name)
- #for i in settings.keys():
- # print i
return settings
- def registerPlugin(self, plugin_name):
- return self.daemon().RegisterPlugin(plugin_name)
-
- def unRegisterPlugin(self, plugin_name):
- return self.daemon().UnRegisterPlugin(plugin_name)
+# "Enable" toggling in GUI is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD
+# def registerPlugin(self, plugin_name):
+# return self.daemon().RegisterPlugin(plugin_name)
+#
+# def unRegisterPlugin(self, plugin_name):
+# return self.daemon().UnRegisterPlugin(plugin_name)
def setPluginSettings(self, plugin_name, plugin_settings):
return self.daemon().SetPluginSettings(plugin_name, plugin_settings)
@@ -206,6 +208,6 @@ class DBusManager(gobject.GObject):
def setSettings(self, settings):
# FIXME: STUB!!!!
- print "setSettings stub"
+ log1("setSettings stub")
retval = self.daemon().SetSettings(self.daemon().GetSettings())
print ">>>", retval
diff --git a/src/Gui/CCDumpList.py b/src/Gui/CCDumpList.py
index 09191f5..a8657e0 100644
--- a/src/Gui/CCDumpList.py
+++ b/src/Gui/CCDumpList.py
@@ -6,7 +6,6 @@ class DumpList(list):
"""Class to store list of debug dumps"""
def __init__(self,dbus_manager=None):
self.dm = dbus_manager
- self.ddict = {}
def load(self):
if self.dm:
@@ -21,7 +20,6 @@ class DumpList(list):
# print "DumpList adding %s:%s" % (column,row[column])
entry.__dict__[column] = row[column]
self.append(entry)
- self.ddict[entry.getUUID()] = entry
except Exception, e:
# FIXME handle exception better
# this is just temporary workaround for rhbz#543725
diff --git a/src/Gui/CCMainWindow.py b/src/Gui/CCMainWindow.py
index 77ce3d3..5ffc027 100644
--- a/src/Gui/CCMainWindow.py
+++ b/src/Gui/CCMainWindow.py
@@ -2,6 +2,7 @@
import sys
import os
import pwd
+import getopt
import pygtk
pygtk.require("2.0")
import gobject
@@ -12,6 +13,12 @@ except RuntimeError,e:
print e
os.exit()
import gtk.glade
+try:
+ import rpm
+except Exception, ex:
+ rpm = None
+
+from ConfBackend import getCurrentConfBackend, ConfBackendInitError
import CCDBusBackend
from CC_gui_functions import *
from CCDumpList import getDumpList, DumpList
@@ -21,12 +28,7 @@ from SettingsDialog import SettingsDialog
from CCReport import Report
from PluginList import getPluginInfoList
import ABRTExceptions
-from abrt_utils import _
-
-try:
- import rpm
-except Exception, ex:
- rpm = None
+from abrt_utils import _, init_logging, log, log1, log2
class MainWindow():
@@ -41,11 +43,10 @@ class MainWindow():
sys.exit()
except Exception, e:
# show error message if connection fails
- # FIXME add an option to start the daemon
gui_error_message("%s" % e)
sys.exit()
#Set the Glade file
- self.gladefile = "%s%sccgui.glade" % (sys.path[0],"/")
+ self.gladefile = "%s/ccgui.glade" % sys.path[0]
self.wTree = gtk.glade.XML(self.gladefile)
#Get the Main Window, and connect the "destroy" event
@@ -69,9 +70,9 @@ class MainWindow():
#icon, package_name, application, date, crash_rate, user, is_reported, ?object?
self.dumpsListStore = gtk.ListStore(gtk.gdk.Pixbuf, str,str,str,str,str,bool, object)
# set filter
- self.modelfilter = self.dumpsListStore.filter_new()
- self.modelfilter.set_visible_func(self.filter_dumps, None)
- self.dlist.set_model(self.modelfilter)
+ modelfilter = self.dumpsListStore.filter_new()
+ modelfilter.set_visible_func(self.filter_dumps, None)
+ self.dlist.set_model(modelfilter)
# add pixbuff separatelly
icon_column = gtk.TreeViewColumn(_("Icon"))
icon_column.cell = gtk.CellRendererPixbuf()
@@ -233,9 +234,11 @@ class MainWindow():
# it is not informative (no URL to the report)
for message in dump.getMessage().split('\n'):
if message:
- if "http" in message[0:5] or "file:///"[0:8] in message:
- message = "<a href=\"%s\">%s</a>" % (message, message)
+ #Doesn't work (far too easy to make it worse, not better):
+ #if "http" in message[0:5] or "file:///"[0:8] in message:
+ # message = "<a href=\"%s\">%s</a>" % (message, message)
report_label += "%s\n" % message
+ log2("setting markup '%s'", report_label)
self.wTree.get_widget("lReported").set_markup(report_label)
else:
self.wTree.get_widget("lReported").set_markup(_("<b>Not reported!</b>"))
@@ -297,13 +300,20 @@ class MainWindow():
try:
self.pBarWindow.show_all()
self.timer = gobject.timeout_add(100, self.progress_update_cb)
- reporters_settings = {}
- # self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True)
- # don't force refresh!
- self.pluginlist = getPluginInfoList(self.ccdaemon)
- for plugin in self.pluginlist.getReporterPlugins():
- reporters_settings[str(plugin)] = plugin.Settings
+ # Old way: it needs to talk to daemon
+ #reporters_settings = {}
+ ## self.pluginlist = getPluginInfoList(self.ccdaemon, refresh=True)
+ ## don't force refresh!
+ #self.pluginlist = getPluginInfoList(self.ccdaemon)
+ #for plugin in self.pluginlist.getReporterPlugins():
+ # reporters_settings[str(plugin)] = plugin.Settings
+ reporters_settings = getCurrentConfBackend().load_all()
+ log2("Report(result,settings):")
+ log2(" result:%s", str(result))
+ # Careful, this will print reporters_settings["Password"] too
+ log2(" settings:%s", str(reporters_settings))
self.ccdaemon.Report(result, reporters_settings)
+ log2("Report() returned")
#self.hydrate()
except Exception, e:
gui_error_message(_("Reporting failed!\n%s" % e))
@@ -381,8 +391,19 @@ class MainWindow():
self.window.present()
if __name__ == "__main__":
+ try:
+ opts, args = getopt.getopt(sys.argv[1:], "v")
+ except getopt.GetoptError, err:
+ print str(err) # prints something like "option -a not recognized"
+ sys.exit(2)
+ verbose = 0
+ for opt, arg in opts:
+ if opt == "-v":
+ verbose += 1
+ init_logging("abrt-gui", verbose)
+ log1("log level:%d", verbose)
+
cc = MainWindow()
cc.hydrate()
cc.show()
gtk.main()
-
diff --git a/src/Gui/CCReporterDialog.py b/src/Gui/CCReporterDialog.py
index 09a9c91..ab6ad0f 100644
--- a/src/Gui/CCReporterDialog.py
+++ b/src/Gui/CCReporterDialog.py
@@ -12,7 +12,7 @@ from ABRTPlugin import PluginInfo
from PluginSettingsUI import PluginSettingsUI
from PluginList import getPluginInfoList
#from CCDumpList import getDumpList, DumpList
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
# FIXME - create method or smth that returns type|editable|content
CD_TYPE = 0
@@ -131,7 +131,7 @@ class ReporterDialog():
ui.dehydrate()
if plugin.Settings.check():
try:
- plugin.save_settings()
+ plugin.save_settings_on_client_side()
except Exception, e:
gui_error_message(_("Can't save plugin settings:\n %s" % e))
box = image.get_parent()
diff --git a/src/Gui/CC_gui_functions.py b/src/Gui/CC_gui_functions.py
index 0532ab7..0379f20 100644
--- a/src/Gui/CC_gui_functions.py
+++ b/src/Gui/CC_gui_functions.py
@@ -15,13 +15,15 @@ try:
import rpm
except:
rpm = None
+from abrt_utils import _, log, log1, log2
+
def on_url_clicked(label, url):
import gnomevfs
file_mimetype = gnomevfs.get_mime_type(url)
default_app = gnomevfs.mime_get_default_application(file_mimetype)
if default_app:
- #print "Default Application:", default_app[2]
+ log2("default application:%s", default_app[2])
subprocess.Popen([default_app[2], url])
def gui_report_dialog ( report_status_dict, parent_dialog,
@@ -160,8 +162,8 @@ def gui_question_dialog ( message, parent_dialog=None,
dialog.destroy()
return ret
-def get_icon_for_package(theme,package):
- #print package
+def get_icon_for_package(theme, package):
+ log2("get_icon_for_package('%s')", package)
try:
return theme.load_icon(package, 22, gtk.ICON_LOOKUP_USE_BUILTIN)
except:
@@ -169,7 +171,7 @@ def get_icon_for_package(theme,package):
if not rpm:
return None
ts = rpm.TransactionSet()
- mi = ts.dbMatch( 'name', package )
+ mi = ts.dbMatch('name', package)
possible_icons = []
icon_filename = ""
filenames = ""
@@ -180,19 +182,19 @@ def get_icon_for_package(theme,package):
if filename.rfind(".png") != -1:
possible_icons.append(filename)
if filename.rfind(".desktop") != -1:
- #print filename
+ log2("desktop file:'%s'", filename)
desktop_file = open(filename, 'r')
lines = desktop_file.readlines()
for line in lines:
if line.find("Icon=") != -1:
- #print line[5:-1]
+ log2("Icon='%s'", line[5:-1])
icon_filename = line[5:-1]
break
desktop_file.close()
# .dektop file found
for filename in h['filenames']:
if filename.rfind("%s.png" % icon_filename) != -1:
- #print filename
+ log2("png file:'%s'", filename)
icon_filename = filename
break
#we didn't find the .desktop file
@@ -205,8 +207,8 @@ def get_icon_for_package(theme,package):
if icon_filename:
break
if icon_filename:
- #print "icon created form %s" % icon_filename
- return gtk.gdk.pixbuf_new_from_file_at_size(icon_filename,22,22)
+ log1("icon created from %s", icon_filename)
+ return gtk.gdk.pixbuf_new_from_file_at_size(icon_filename, 22, 22)
else:
return None
diff --git a/src/Gui/ConfBackend.py b/src/Gui/ConfBackend.py
index 5e26f3e..0d47760 100644
--- a/src/Gui/ConfBackend.py
+++ b/src/Gui/ConfBackend.py
@@ -1,6 +1,8 @@
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
-#FIXME: add some backend factory
+# Doc on Gnome keyring API:
+# http://library.gnome.org/devel/gnome-keyring/stable/
+# Python bindings are in gnome-python2-desktop package
try:
import gnomekeyring as gkey
@@ -38,63 +40,182 @@ class ConfBackend(object):
raise NotImplementedError
+# We use Gnome keyring in the following way:
+# we store passwords for each plugin in a key named "abrt:<plugin_name>".
+# The value of the key becomes the value of "Password" setting.
+# Other settings (if plugin has them) are stored as attributes of this key.
+#
+# Example: Key "abrt:Bugzilla" with bugzilla password as value, and with attributes:
+#
+# Application: abrt
+# AbrtPluginInfo: Bugzilla
+# NoSSLVerify: yes
+# Login: user@host.com
+# BugzillaURL: https://host.with.bz.com/
+#
+# Attributes "Application" and "AbrtPluginInfo" are special, they are used
+# for efficient key retrieval via keyring API find_items_sync() function.
+
+g_default_key_ring = None
+
class ConfBackendGnomeKeyring(ConfBackend):
def __init__(self):
+ global g_default_key_ring
+
ConfBackend.__init__(self)
- if not gkey.is_available():
+ if g_default_key_ring:
+ return
+ if not gkey or not gkey.is_available():
raise ConfBackendInitError(_("Can't connect to Gnome Keyring daemon"))
try:
- self.default_key_ring = gkey.get_default_keyring_sync()
+ g_default_key_ring = gkey.get_default_keyring_sync()
except:
# could happen if keyring daemon is running, but we run gui under
- # user who is not owner is the running session - using su
+ # user who is not the owner of the running session - using su
raise ConfBackendInitError(_("Can't get default keyring"))
def save(self, name, settings):
settings_tmp = settings.copy()
+ settings_tmp["Application"] = "abrt"
settings_tmp["AbrtPluginInfo"] = name
- password = ""
- item_list = []
+ # delete all keyring items containg "AbrtPluginInfo":"<plugin_name>",
+ # so we always have only 1 item per plugin
try:
- item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, {"AbrtPluginInfo":str(name)})
+ item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, { "AbrtPluginInfo": str(name) })
+ for item in item_list:
+ log2("found old keyring item: ring:'%s' item_id:%s attrs:%s", item.keyring, item.item_id, str(item.attributes))
+ log2("deleting it from keyring '%s'", g_default_key_ring)
+ gkey.item_delete_sync(g_default_key_ring, item.item_id)
except gkey.NoMatchError:
# nothing found
pass
except gkey.DeniedError:
- raise ConfBackendSaveError(_("Acces to gnome-keyring has been denied, plugins settings won't be saved."))
-
- # delete all items containg "AbrtPluginInfo":<plugin_name>, so we always have only 1 item per plugin
- for item in item_list:
- gkey.item_delete_sync(self.default_key_ring, item.item_id)
-
+ raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved."))
+ # if plugin has a "Password" setting, we handle it specially: in keyring,
+ # it is stored as item.secret, not as one of attributes
+ password = ""
if "Password" in settings_tmp:
password = settings_tmp["Password"]
del settings_tmp["Password"]
+ # store new settings for this plugin as one keyring item
try:
- gkey.item_create_sync(self.default_key_ring,
+ gkey.item_create_sync(g_default_key_ring,
gkey.ITEM_GENERIC_SECRET,
- "abrt:%s" % name,
- settings_tmp,
- password,
+ "abrt:%s" % name, # display_name
+ settings_tmp, # attrs
+ password, # secret
True)
except gkey.DeniedError, e:
- raise ConfBackendSaveError(_("Acces to gnome-keyring has been denied, plugins settings won't be saved."))
+ raise ConfBackendSaveError(_("Access to gnome-keyring has been denied, plugins settings won't be saved."))
def load(self, name):
item_list = None
try:
+ log2("looking for keyring items with 'AbrtPluginInfo:%s' attr", str(name))
item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, {"AbrtPluginInfo":str(name)})
+ for item in item_list:
+ # gnome keyring is weeeeird. why display_name, type, mtime, ctime
+ # aren't available in find_items_sync() results? why we need to
+ # get them via additional call, item_get_info_sync()?
+ # internally, item has GNOME_KEYRING_TYPE_FOUND type,
+ # and info has GNOME_KEYRING_TYPE_ITEM_INFO type.
+ # why not use the same type for both?
+ #
+ # and worst of all, this information took four hours of googling...
+ #
+ #info = gkey.item_get_info_sync(item.keyring, item.item_id)
+ log2("found keyring item: ring:'%s' item_id:%s attrs:%s", # "secret:'%s' display_name:'%s'"
+ item.keyring, item.item_id, str(item.attributes) #, item.secret, info.get_display_name()
+ )
except gkey.NoMatchError:
# nothing found
pass
-
if item_list:
retval = item_list[0].attributes.copy()
retval["Password"] = item_list[0].secret
return retval
- else:
- return {}
- #for i in item_list:
- # for attr in i.attributes:
- # print attr, i.attributes[attr]
+ return {}
+
+ # This routine loads setting for all plugins. It doesn't need plugin name.
+ # Thus we can avoid talking to abrtd just in order to get plugin names.
+ def load_all(self):
+ retval = {}
+ item_list = {}
+
+ # UGLY compat cludge for users who has saved items without "Application" attr
+ # (abrt <= 1.0.3 was saving those)
+ item_ids = gkey.list_item_ids_sync(g_default_key_ring)
+ log2("all keyring item ids:%s", item_ids)
+ for item_id in item_ids:
+ info = gkey.item_get_info_sync(g_default_key_ring, item_id)
+ attrs = gkey.item_get_attributes_sync(g_default_key_ring, item_id)
+ log2("keyring item %s: attrs:%s", item_id, str(attrs))
+ if "AbrtPluginInfo" in attrs:
+ if not "Application" in attrs:
+ log2("updating old-style keyring item")
+ attrs["Application"] = "abrt"
+ try:
+ gkey.item_set_attributes_sync(g_default_key_ring, item_id, attrs)
+ except:
+ log2("error updating old-style keyring item")
+ plugin_name = attrs["AbrtPluginInfo"]
+ # If plugin has a "Password" setting, we handle it specially: in keyring,
+ # it is stored as item.secret, not as one of attributes
+ if info.get_secret():
+ attrs["Password"] = info.get_secret()
+ # avoiding sending useless duplicate info over dbus...
+ del attrs["AbrtPluginInfo"]
+ try:
+ del attrs["Application"]
+ except:
+ pass
+ retval[plugin_name] = attrs;
+ # end of UGLY compat cludge
+
+ try:
+ log2("looking for keyring items with 'Application:abrt' attr")
+ item_list = gkey.find_items_sync(gkey.ITEM_GENERIC_SECRET, { "Application": "abrt" })
+ except gkey.NoMatchError:
+ # nothing found
+ pass
+ for item in item_list:
+ # gnome keyring is weeeeird. why display_name, type, mtime, ctime
+ # aren't available in find_items_sync() results? why we need to
+ # get them via additional call, item_get_info_sync()?
+ # internally, item has GNOME_KEYRING_TYPE_FOUND type,
+ # and info has GNOME_KEYRING_TYPE_ITEM_INFO type.
+ # why not use the same type for both?
+ #
+ # and worst of all, this information took four hours of googling...
+ #
+ #info = gkey.item_get_info_sync(item.keyring, item.item_id)
+ log2("found keyring item: ring:%s item_id:%s attrs:%s", # "secret:%s display_name:'%s'"
+ item.keyring, item.item_id, str(item.attributes) #, item.secret, info.get_display_name()
+ )
+ attrs = item.attributes.copy()
+ if "AbrtPluginInfo" in attrs:
+ plugin_name = attrs["AbrtPluginInfo"]
+ # If plugin has a "Password" setting, we handle it specially: in keyring,
+ # it is stored as item.secret, not as one of attributes
+ if item.secret:
+ attrs["Password"] = item.secret
+ # avoiding sending useless duplicate info over dbus...
+ del attrs["AbrtPluginInfo"]
+ try:
+ del attrs["Application"]
+ except:
+ pass
+ retval[plugin_name] = attrs;
+ return retval
+
+
+# Rudimentary backend factory
+
+currentConfBackend = None
+
+def getCurrentConfBackend():
+ global currentConfBackend
+ if not currentConfBackend:
+ currentConfBackend = ConfBackendGnomeKeyring()
+ return currentConfBackend
diff --git a/src/Gui/PluginList.py b/src/Gui/PluginList.py
index e57040d..d2232bb 100644
--- a/src/Gui/PluginList.py
+++ b/src/Gui/PluginList.py
@@ -1,31 +1,27 @@
# -*- coding: utf-8 -*-
import CCDBusBackend
from ABRTPlugin import PluginInfo, PluginSettings
+from abrt_utils import _, log, log1, log2
class PluginInfoList(list):
"""Class to store list of PluginInfos"""
def __init__(self,dbus_manager=None):
self.dm = dbus_manager
- self.ddict = {}
def load(self):
if self.dm:
- #print "loading PluginList"
rows = self.dm.getPluginsInfo()
- #print rows
- for row in rows:
+ for plugin_name in rows:
+ row = rows[plugin_name]
entry = PluginInfo()
- for column in row:
- #print "PluginInfoList adding %s:%s" % (column,row[column])
- entry.__dict__[column] = row[column]
- if entry.Enabled == "yes":
- #entry.Settings = PluginSettings(self.dm.getPluginSettings(str(entry)))
- default_settings = self.dm.getPluginSettings(str(entry))
- entry.load_settings(default_settings)
+ for attr_name in row:
+ log2("PluginInfoList: adding %s[%s]:%s", plugin_name, attr_name, row[attr_name])
+ entry.__dict__[attr_name] = row[attr_name]
+ daemon_settings = self.dm.getPluginSettings(plugin_name)
+ entry.load_daemon_settings(daemon_settings)
self.append(entry)
- self.ddict[entry.getName()] = entry
else:
- print "db == None!"
+ log("PluginInfoList: db == None")
def getEnabledPlugins(self):
return [x for x in self if x["Enabled"] == 'yes']
diff --git a/src/Gui/PluginSettingsUI.py b/src/Gui/PluginSettingsUI.py
index a26f87f..c324b31 100644
--- a/src/Gui/PluginSettingsUI.py
+++ b/src/Gui/PluginSettingsUI.py
@@ -1,5 +1,5 @@
import gtk
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
class PluginSettingsUI(gtk.Dialog):
def __init__(self, pluginfo, parent=None):
diff --git a/src/Gui/PluginsSettingsDialog.py b/src/Gui/PluginsSettingsDialog.py
index 8453385..611a8c5 100644
--- a/src/Gui/PluginsSettingsDialog.py
+++ b/src/Gui/PluginsSettingsDialog.py
@@ -4,14 +4,16 @@ from PluginList import getPluginInfoList, PluginInfoList
from CC_gui_functions import *
from PluginSettingsUI import PluginSettingsUI
from ABRTPlugin import PluginSettings, PluginInfo
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
+
class PluginsSettingsDialog:
def __init__(self, parent, daemon):
#print "Settings dialog init"
self.ccdaemon = daemon
+
self.builder = gtk.Builder()
- builderfile = "%s%ssettings.glade" % (sys.path[0],"/")
+ builderfile = "%s%ssettings.glade" % (sys.path[0], "/")
#print builderfile
try:
self.builder.add_from_file(builderfile)
@@ -22,42 +24,41 @@ class PluginsSettingsDialog:
raise Exception(_("Can't load gui description for SettingsDialog!"))
#self.window.set_parent(parent)
- self.pluginlist = self.builder.get_object("tvSettings")
+ self.pluginlist = self.builder.get_object("tvSettings") # a TreeView
# cell_text, toggle_active, toggle_visible, group_name_visible, color, plugin
self.pluginsListStore = gtk.TreeStore(str, bool, bool, bool, str, object)
# set filter
- self.modelfilter = self.pluginsListStore.filter_new()
- self.modelfilter.set_visible_func(self.filter_plugins, None)
- self.pluginlist.set_model(self.modelfilter)
- # ===============================================
- columns = [None]*1
- columns[0] = gtk.TreeViewColumn(_("Name"))
+ modelfilter = self.pluginsListStore.filter_new()
+ modelfilter.set_visible_func(self.filter_plugins, None)
+ self.pluginlist.set_model(modelfilter)
- # create list
- for column in columns:
- n = self.pluginlist.append_column(column)
- column.cell = gtk.CellRendererText()
- column.gray_background = gtk.CellRendererText()
- column.pack_start(column.cell, True)
- column.pack_start(column.gray_background, True)
- column.set_attributes(column.cell, markup=(n-1), visible=2)
- column.set_attributes(column.gray_background, visible=3, cell_background=4)
- column.set_resizable(True)
+ # Create/configure columns and add them to pluginlist
+ # column "name" has two kind of cells:
+ column = gtk.TreeViewColumn(_("Name"))
+ # cells for individual plugins (white)
+ cell_name = gtk.CellRendererText()
+ column.pack_start(cell_name, True)
+ column.set_attributes(cell_name, markup=0, visible=2) # show 0th field (plugin name) from data items if 2th field is true
+ # cells for plugin types (gray)
+ cell_plugin_type = gtk.CellRendererText()
+ column.pack_start(cell_plugin_type, True)
+ column.add_attribute(cell_plugin_type, "visible", 3)
+ column.add_attribute(cell_plugin_type, "markup", 0)
+ column.add_attribute(cell_plugin_type, "cell_background", 4)
+ # column "name" is ready, insert
+ column.set_resizable(True)
+ self.pluginlist.append_column(column)
- # toggle
- group_name_renderer = gtk.CellRendererText()
- toggle_renderer = gtk.CellRendererToggle()
- toggle_renderer.set_property('activatable', True)
- toggle_renderer.connect( 'toggled', self.on_enabled_toggled, self.pluginsListStore )
- column = gtk.TreeViewColumn(_('Enabled'))
- column.pack_start(toggle_renderer, True)
- column.pack_start(group_name_renderer, True)
- column.add_attribute( toggle_renderer, "active", 1)
- column.add_attribute( toggle_renderer, "visible", 2)
- column.add_attribute( group_name_renderer, "visible", 3)
- column.add_attribute( group_name_renderer, "markup", 0)
- column.add_attribute( group_name_renderer, "cell_background", 4)
- self.pluginlist.insert_column(column, 0)
+# "Enable" toggle column is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD
+# column = gtk.TreeViewColumn(_("Enabled"))
+# # column "enabled" has one kind of cells:
+# cell_toggle_enable = gtk.CellRendererToggle()
+# cell_toggle_enable.set_property("activatable", True)
+# cell_toggle_enable.connect("toggled", self.on_enabled_toggled, self.pluginsListStore)
+# column.pack_start(cell_toggle_enable, True)
+# column.add_attribute(cell_toggle_enable, "active", 1)
+# column.add_attribute(cell_toggle_enable, "visible", 2)
+# self.pluginlist.append_column(column)
#connect signals
self.pluginlist.connect("cursor-changed", self.on_tvDumps_cursor_changed)
@@ -65,27 +66,29 @@ class PluginsSettingsDialog:
self.builder.get_object("bClose").connect("clicked", self.on_bClose_clicked)
self.builder.get_object("bConfigurePlugin").set_sensitive(False)
- def on_enabled_toggled(self,cell, path, model):
- plugin = model[path][model.get_n_columns()-1]
- if plugin:
- if model[path][1]:
- #print "self.ccdaemon.UnRegisterPlugin(%s)" % (plugin.getName())
- self.ccdaemon.unRegisterPlugin(plugin.getName())
- # FIXME: create class plugin and move this into method Plugin.Enable()
- plugin.Enabled = "no"
- plugin.Settings = None
- else:
- #print "self.ccdaemon.RegisterPlugin(%s)" % (model[path][model.get_n_columns()-1])
- self.ccdaemon.registerPlugin(plugin.getName())
- # FIXME: create class plugin and move this into method Plugin.Enable()
- plugin.Enabled = "yes"
- default_settings = self.ccdaemon.getPluginSettings(plugin.getName())
- plugin.Settings = PluginSettings()
- plugin.Settings.load(plugin.getName(), default_settings)
- model[path][1] = not model[path][1]
+# "Enable" toggle column is disabled for now. Grep for PLUGIN_DYNAMIC_LOAD_UNLOAD
+# def on_enabled_toggled(self,cell, path, model):
+# plugin = model[path][model.get_n_columns()-1]
+# if plugin:
+# if model[path][1]:
+# #print "self.ccdaemon.UnRegisterPlugin(%s)" % (plugin.getName())
+# self.ccdaemon.unRegisterPlugin(plugin.getName())
+# # FIXME: create class plugin and move this into method Plugin.Enable()
+# plugin.Enabled = "no"
+# plugin.Settings = None
+# else:
+# #print "self.ccdaemon.RegisterPlugin(%s)" % (model[path][model.get_n_columns()-1])
+# self.ccdaemon.registerPlugin(plugin.getName())
+# # FIXME: create class plugin and move this into method Plugin.Enable()
+# plugin.Enabled = "yes"
+# default_settings = self.ccdaemon.getPluginSettings(plugin.getName())
+# plugin.Settings = PluginSettings()
+# plugin.Settings.load(plugin.getName(), default_settings)
+# model[path][1] = not model[path][1]
def filter_plugins(self, model, miter, data):
return True
+
def hydrate(self):
#print "settings hydrate"
self.pluginsListStore.clear()
@@ -96,15 +99,22 @@ class PluginsSettingsDialog:
except Exception, e:
print e
#gui_error_message("Error while loading plugins info, please check if abrt daemon is running\n %s" % e)
+ return
plugin_rows = {}
for plugin_type in PluginInfo.types.keys():
- it = self.pluginsListStore.append(None, ["<b>%s</b>" % (PluginInfo.types[plugin_type]),0 , 0, 1,"gray", None])
+ it = self.pluginsListStore.append(None,
+ ["<b>%s</b>" % PluginInfo.types[plugin_type], 0, 0, 1, "gray", None])
plugin_rows[plugin_type] = it
for entry in pluginlist:
- n = self.pluginsListStore.append(plugin_rows[entry.getType()],["<b>%s</b>\n%s" % (entry.getName(), entry.Description), entry.Enabled == "yes", 1, 0, "white", entry])
+ if entry.Description:
+ text = "<b>%s</b>\n%s" % (entry.getName(), entry.Description)
+ else:
+ # non-loaded plugins have empty description
+ text = "<b>%s</b>" % entry.getName()
+ self.pluginsListStore.append(plugin_rows[entry.getType()],
+ [text, entry.Enabled == "yes", 1, 0, "white", entry])
self.pluginlist.expand_all()
-
def dehydrate(self):
# we have nothing to save, plugin's does the work
pass
@@ -135,7 +145,7 @@ class PluginsSettingsDialog:
ui.dehydrate()
if pluginfo.Settings:
try:
- pluginfo.save_settings()
+ pluginfo.save_settings_on_client_side()
# FIXME: do we need to call this? all reporters set their settings
# when Report() is called
self.ccdaemon.setPluginSettings(pluginfo.getName(), pluginfo.Settings)
@@ -146,7 +156,7 @@ class PluginsSettingsDialog:
elif response == gtk.RESPONSE_CANCEL:
pass
else:
- print _("unknown response from settings dialog")
+ log("unknown response from settings dialog:%d", response)
ui.destroy()
def on_bClose_clicked(self, button):
diff --git a/src/Gui/SettingsDialog.py b/src/Gui/SettingsDialog.py
index c2b292f..893c23f 100644
--- a/src/Gui/SettingsDialog.py
+++ b/src/Gui/SettingsDialog.py
@@ -3,7 +3,7 @@ import gtk
from PluginList import getPluginInfoList
from CC_gui_functions import *
#from PluginSettingsUI import PluginSettingsUI
-from abrt_utils import _
+from abrt_utils import _, log, log1, log2
#FIXME: create a better struct, to automatize hydrate/dehydrate process
diff --git a/src/Gui/abrt_utils.py b/src/Gui/abrt_utils.py
index 6122b9c..2fabb54 100644
--- a/src/Gui/abrt_utils.py
+++ b/src/Gui/abrt_utils.py
@@ -1,16 +1,37 @@
+import sys
import gtk.glade
+
PROGNAME = "abrt"
+g_verbose = 0
+
import locale
-try:
- locale.setlocale (locale.LC_ALL, "")
-except locale.Error, e:
- import os
- os.environ['LC_ALL'] = 'C'
- locale.setlocale (locale.LC_ALL, "")
import gettext
-gettext.bind_textdomain_codeset(PROGNAME,locale.nl_langinfo(locale.CODESET))
-gettext.bindtextdomain(PROGNAME, '/usr/share/locale')
-gtk.glade.bindtextdomain(PROGNAME, '/usr/share/locale')
-gtk.glade.textdomain(PROGNAME)
-gettext.textdomain(PROGNAME)
+
_ = lambda x: gettext.lgettext(x)
+
+def init_logging(progname, v):
+ global PROGNAME, g_verbose
+ PROGNAME = progname
+ g_verbose = v
+ try:
+ locale.setlocale(locale.LC_ALL, "")
+ except locale.Error, e:
+ import os
+ os.environ['LC_ALL'] = 'C'
+ locale.setlocale(locale.LC_ALL, "")
+ gettext.bind_textdomain_codeset(PROGNAME, locale.nl_langinfo(locale.CODESET))
+ gettext.bindtextdomain(PROGNAME, '/usr/share/locale')
+ gtk.glade.bindtextdomain(PROGNAME, '/usr/share/locale')
+ gtk.glade.textdomain(PROGNAME)
+ gettext.textdomain(PROGNAME)
+
+def log(fmt, *args):
+ sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args))
+
+def log1(fmt, *args):
+ if g_verbose >= 1:
+ sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args))
+
+def log2(fmt, *args):
+ if g_verbose >= 2:
+ sys.stderr.write("%s: %s\n" % (PROGNAME, fmt % args))
diff --git a/src/Hooks/Makefile.am b/src/Hooks/Makefile.am
index 7581971..2b04990 100644
--- a/src/Hooks/Makefile.am
+++ b/src/Hooks/Makefile.am
@@ -1,9 +1,10 @@
libexec_PROGRAMS = abrt-hook-ccpp abrt-hook-python
bin_PROGRAMS = dumpoops
-# CCpp
+# abrt-hook-ccpp
abrt_hook_ccpp_SOURCES = \
- CCpp.cpp
+ abrt-hook-ccpp.cpp \
+ hooklib.h hooklib.cpp
abrt_hook_ccpp_CPPFLAGS = \
-I$(srcdir)/../../inc \
-I$(srcdir)/../../lib/Utils \
@@ -34,7 +35,8 @@ dumpoops_LDADD = \
# abrt-hook-python
abrt_hook_python_SOURCES = \
- abrt-hook-python.cpp
+ abrt-hook-python.cpp \
+ hooklib.h hooklib.cpp
abrt_hook_python_CPPFLAGS = \
-I$(srcdir)/../../inc \
-I$(srcdir)/../../lib/Utils \
diff --git a/src/Hooks/CCpp.cpp b/src/Hooks/abrt-hook-ccpp.cpp
index 3a13358..1c91dc8 100644
--- a/src/Hooks/CCpp.cpp
+++ b/src/Hooks/abrt-hook-ccpp.cpp
@@ -1,5 +1,5 @@
/*
- CCpp.cpp - the hook for C/C++ crashing program
+ abrt-hook-ccpp.cpp - the hook for C/C++ crashing program
Copyright (C) 2009 Zdenek Prikryl (zprikryl@redhat.com)
Copyright (C) 2009 RedHat inc.
@@ -19,6 +19,7 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "abrtlib.h"
+#include "hooklib.h"
#include "DebugDump.h"
#include "ABRTException.h"
#include <syslog.h>
@@ -44,17 +45,17 @@ static char* malloc_readlink(const char *linkname)
static char* get_executable(pid_t pid)
{
- char buf[sizeof("/proc/%u/exe") + sizeof(int)*3];
+ char buf[sizeof("/proc/%lu/exe") + sizeof(long)*3];
- sprintf(buf, "/proc/%u/exe", (int)pid);
+ sprintf(buf, "/proc/%lu/exe", (long)pid);
return malloc_readlink(buf);
}
static char* get_cwd(pid_t pid)
{
- char buf[sizeof("/proc/%u/cwd") + sizeof(int)*3];
+ char buf[sizeof("/proc/%lu/cwd") + sizeof(long)*3];
- sprintf(buf, "/proc/%u/cwd", (int)pid);
+ sprintf(buf, "/proc/%lu/cwd", (long)pid);
return malloc_readlink(buf);
}
@@ -63,12 +64,12 @@ int main(int argc, char** argv)
int fd;
struct stat sb;
- const char* program_name = argv[0];
if (argc < 5)
{
+ const char* program_name = argv[0];
error_msg_and_die("Usage: %s: DUMPDIR PID SIGNO UID CORE_SIZE_LIMIT", program_name);
}
- openlog("abrt", 0, LOG_DAEMON);
+ openlog("abrt", LOG_PID, LOG_DAEMON);
logmode = LOGMODE_SYSLOG;
errno = 0;
@@ -113,80 +114,31 @@ int main(int argc, char** argv)
char* executable = get_executable(pid);
if (executable == NULL)
{
- error_msg_and_die("can't read /proc/%u/exe link", (int)pid);
+ error_msg_and_die("can't read /proc/%lu/exe link", (long)pid);
}
if (strstr(executable, "/abrt-hook-ccpp"))
{
- error_msg_and_die("pid %u is '%s', not dumping it to avoid recursion",
- (int)pid, executable);
+ error_msg_and_die("pid %lu is '%s', not dumping it to avoid recursion",
+ (long)pid, executable);
}
/* Parse abrt.conf and plugins/CCpp.conf */
unsigned setting_MaxCrashReportsSize = 0;
bool setting_MakeCompatCore = false;
- bool abrt_conf = true;
- FILE *fp = fopen(CONF_DIR"/abrt.conf", "r");
- if (fp)
- {
- char line[256];
- while (1)
- {
- if (fgets(line, sizeof(line), fp) == NULL)
- {
- /* Next .conf file plz */
- if (abrt_conf)
- {
- abrt_conf = false;
- fp = fopen(CONF_DIR"/plugins/CCpp.conf", "r");
- if (fp)
- continue;
- }
- break;
- }
+ parse_conf(CONF_DIR"/plugins/CCpp.conf", &setting_MaxCrashReportsSize, &setting_MakeCompatCore);
- unsigned len = strlen(line);
- if (len > 0 && line[len-1] == '\n')
- line[--len] = '\0';
- const char *p = skip_whitespace(line);
-#undef DIRECTIVE
-#define DIRECTIVE "MaxCrashReportsSize"
- if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
- {
- p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
- if (*p != '=')
- continue;
- p = skip_whitespace(p + 1);
- if (isdigit(*p))
- /* x1.25: go a bit up, so that usual in-daemon trimming
- * kicks in first, and we don't "fight" with it. */
- setting_MaxCrashReportsSize = (unsigned long)xatou(p) * 5 / 4;
- continue;
- }
-#undef DIRECTIVE
-#define DIRECTIVE "MakeCompatCore"
- if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
- {
- p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
- if (*p != '=')
- continue;
- p = skip_whitespace(p + 1);
- setting_MakeCompatCore = string_to_bool(p);
- continue;
- }
-#undef DIRECTIVE
- /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */
- }
- fclose(fp);
+ if (setting_MaxCrashReportsSize > 0)
+ {
+ check_free_space(setting_MaxCrashReportsSize);
}
-
char path[PATH_MAX];
/* Check /var/cache/abrt/last-ccpp marker, do not dump repeated crashes
* if they happen too often. Else, write new marker value.
*/
snprintf(path, sizeof(path), "%s/last-ccpp", dddir);
- fd = open(path, O_RDWR | O_CREAT, 0666);
+ fd = open(path, O_RDWR | O_CREAT, 0600);
if (fd >= 0)
{
int sz;
@@ -232,7 +184,7 @@ int main(int argc, char** argv)
* but it does not log file name */
error_msg_and_die("error saving coredump to %s", path);
}
- log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size);
+ log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size);
return 0;
}
@@ -240,7 +192,7 @@ int main(int argc, char** argv)
const char *signame = strsignal(signal_no);
char *reason = xasprintf("Process was terminated by signal %s (%s)", signal_str, signame ? signame : signal_str);
- snprintf(path, sizeof(path), "%s/ccpp-%ld-%u", dddir, (long)time(NULL), (int)pid);
+ snprintf(path, sizeof(path), "%s/ccpp-%ld-%lu", dddir, (long)time(NULL), (long)pid);
CDebugDump dd;
dd.Create(path, uid);
dd.SaveText(FILENAME_ANALYZER, "CCpp");
@@ -263,6 +215,10 @@ int main(int argc, char** argv)
dd.Close();
perror_msg_and_die("can't open '%s'", path);
}
+//TODO: chown to uid:abrt?
+//Currently it is owned by 0:0 but is readable by anyone, so the owner
+//of the crashed binary still can access it, as he has
+//r-x access to the dump dir.
core_size = copyfd_eof(STDIN_FILENO, core_fd);
if (core_size < 0 || fsync(core_fd) != 0)
{
@@ -275,7 +231,7 @@ int main(int argc, char** argv)
}
lseek(core_fd, 0, SEEK_SET);
/* note: core_fd is still open, we may use it later to copy core to user's dir */
- log("saved core dump of pid %u (%s) to %s (%llu bytes)", (int)pid, executable, path, (long long)core_size);
+ log("saved core dump of pid %lu (%s) to %s (%llu bytes)", (long)pid, executable, path, (long long)core_size);
free(executable);
free(cmdline);
path[len] = '\0'; /* path now contains directory name */
@@ -288,30 +244,10 @@ int main(int argc, char** argv)
*/
dd.Close();
- /* rhbz#539551: "abrt going crazy when crashing process is respawned".
- * Do we want to protect against or ameliorate this? How? Ideas:
- * (1) nice ourself?
- * (2) check total size of dump dir, if it overflows, either abort dump
- * or delete oldest/biggest dumps? [abort would be simpler,
- * abrtd already does "delete on overflow" thing]
- * (3) detect parallel dumps in progress and back off
- * (pause/renice further/??)
- */
-
+ /* rhbz#539551: "abrt going crazy when crashing process is respawned" */
if (setting_MaxCrashReportsSize > 0)
{
- string worst_dir;
- while (1)
- {
- const char *base_dirname = strrchr(path, '/') + 1; /* never NULL */
- /* We exclude our own dump from candidates for deletion (3rd param): */
- double dirsize = get_dirsize_find_largest_dir(DEBUG_DUMPS_DIR, &worst_dir, base_dirname);
- if (dirsize / (1024*1024) < setting_MaxCrashReportsSize || worst_dir == "")
- break;
- log("size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, setting_MaxCrashReportsSize, worst_dir.c_str());
- delete_debug_dump_dir(concat_path_file(DEBUG_DUMPS_DIR, worst_dir.c_str()).c_str());
- worst_dir = "";
- }
+ trim_debug_dumps(setting_MaxCrashReportsSize, path);
}
if (!setting_MakeCompatCore)
@@ -349,7 +285,7 @@ int main(int argc, char** argv)
}
/* Mimic "core.PID" if requested */
- char core_basename[sizeof("core.%u") + sizeof(int)*3] = "core";
+ char core_basename[sizeof("core.%lu") + sizeof(long)*3] = "core";
char buf[] = "0\n";
fd = open("/proc/sys/kernel/core_uses_pid", O_RDONLY);
if (fd >= 0)
@@ -359,7 +295,7 @@ int main(int argc, char** argv)
}
if (strcmp(buf, "1\n") == 0)
{
- sprintf(core_basename, "core.%u", (int)pid);
+ sprintf(core_basename, "core.%lu", (long)pid);
}
/* man core:
@@ -425,7 +361,7 @@ int main(int argc, char** argv)
unlink(core_basename);
return 1;
}
- log("saved core dump of pid %u to %s/%s (%llu bytes)", (int)pid, user_pwd, core_basename, (long long)size);
+ log("saved core dump of pid %lu to %s/%s (%llu bytes)", (long)pid, user_pwd, core_basename, (long long)size);
return 0;
}
diff --git a/src/Hooks/abrt-hook-python.cpp b/src/Hooks/abrt-hook-python.cpp
index 3f79d28..c8a25e3 100644
--- a/src/Hooks/abrt-hook-python.cpp
+++ b/src/Hooks/abrt-hook-python.cpp
@@ -20,27 +20,51 @@
*/
#include <getopt.h>
-#include <unistd.h>
+#include <syslog.h>
/* We can easily get rid of abrtlib (libABRTUtils.so) usage in this file,
* but DebugDump will pull it in anyway */
#include "abrtlib.h"
+#include "hooklib.h"
#include "DebugDump.h"
+#include "ABRTException.h"
#if HAVE_CONFIG_H
# include <config.h>
#endif
#define MAX_BT_SIZE (1024*1024)
+#define MAX_BT_SIZE_STR "1 MB"
static char *pid;
static char *executable;
static char *uuid;
-int main(int argc, char** argv)
+/* Note: "" will return false */
+static bool isxdigit_str(const char *str)
{
- // Error if daemon is not running.
- if (!daemon_is_ok())
- error_msg_and_die("Daemon is not running.");
+ do {
+ if ((*str < '0' || *str > '9') /* not a digit */
+ && ((*str | 0x20) < 'a' || (*str | 0x20) > 'f') /* not A-F or a-f */
+ )
+ {
+ return false;
+ }
+ str++;
+ } while (*str);
+ return true;
+}
+
+static bool printable_str(const char *str)
+{
+ do {
+ if ((unsigned char)(*str) < ' ' || *str == 0x7f)
+ return false;
+ str++;
+ } while (*str);
+ return true;
+}
+int main(int argc, char** argv)
+{
// Parse options
static const struct option longopts[] = {
// name , has_arg , flag, val
@@ -74,49 +98,73 @@ int main(int argc, char** argv)
);
}
}
- if (!pid)
+ if (!pid || !executable || !uuid)
+ goto usage;
+ if (strlen(uuid) > 128 || !isxdigit_str(uuid))
+ goto usage;
+ if (strlen(executable) > PATH_MAX || !printable_str(executable))
goto usage;
-// is it really ok if other params aren't specified? abrtd might get confused...
+ // pid string is sanitized later by xatou()
+
+ openlog("abrt", LOG_PID, LOG_DAEMON);
+ logmode = LOGMODE_SYSLOG;
+
+ // Error if daemon is not running
+ if (!daemon_is_ok())
+ error_msg_and_die("daemon is not running, python crash dump aborted");
+
+ unsigned setting_MaxCrashReportsSize = 0;
+ parse_conf(NULL, &setting_MaxCrashReportsSize, NULL);
+ if (setting_MaxCrashReportsSize > 0)
+ {
+ check_free_space(setting_MaxCrashReportsSize);
+ }
// Read the backtrace from stdin
char *bt = (char*)xmalloc(MAX_BT_SIZE);
ssize_t len = full_read(STDIN_FILENO, bt, MAX_BT_SIZE-1);
if (len < 0)
{
- perror_msg_and_die("Read error");
+ perror_msg_and_die("read error");
}
bt[len] = '\0';
if (len == MAX_BT_SIZE-1)
{
- error_msg("Backtrace size limit exceeded, trimming to 1 MB");
+ error_msg("backtrace size limit exceeded, trimming to " MAX_BT_SIZE_STR);
}
+ // This also checks that pid is a valid numeric string
+ char *cmdline = get_cmdline(xatou(pid)); /* never NULL */
+
// Create directory with the debug dump
char path[PATH_MAX];
snprintf(path, sizeof(path), DEBUG_DUMPS_DIR"/pyhook-%ld-%s",
(long)time(NULL), pid);
-
CDebugDump dd;
- dd.Create(path, geteuid());
- dd.SaveText(FILENAME_ANALYZER, "Python");
- if (executable)
- dd.SaveText(FILENAME_EXECUTABLE, executable);
+ try {
+ dd.Create(path, getuid());
+ } catch (CABRTException &e) {
+ error_msg_and_die("error while creating crash dump %s: %s", path, e.what());
+ }
- pid_t pidt = xatoi(pid);
- char *cmdline = get_cmdline(pidt);
+ dd.SaveText(FILENAME_ANALYZER, "Python");
+ dd.SaveText(FILENAME_EXECUTABLE, executable);
+ dd.SaveText("backtrace", bt);
+ free(bt);
dd.SaveText("cmdline", cmdline);
free(cmdline);
-
- if (uuid)
- dd.SaveText("uuid", uuid);
-
- char uid[sizeof(int) * 3 + 2];
- sprintf(uid, "%d", (int)getuid());
+ dd.SaveText("uuid", uuid);
+ char uid[sizeof(long) * 3 + 2];
+ sprintf(uid, "%lu", (long)getuid());
dd.SaveText("uid", uid);
- dd.SaveText("backtrace", bt);
- free(bt);
dd.Close();
+ log("saved python crash dump of pid %s to %s", pid, path);
+
+ if (setting_MaxCrashReportsSize > 0)
+ {
+ trim_debug_dumps(setting_MaxCrashReportsSize, path);
+ }
return 0;
}
diff --git a/src/Hooks/abrt_exception_handler.py.in b/src/Hooks/abrt_exception_handler.py.in
index a0b0519..e0e1954 100644
--- a/src/Hooks/abrt_exception_handler.py.in
+++ b/src/Hooks/abrt_exception_handler.py.in
@@ -213,7 +213,7 @@ def handleMyException((etype, value, tb)):
text += ("\nLocal variables in innermost frame:\n")
try:
for (key, val) in frame.f_locals.items():
- text += "%s: %s\n" % (key, val)
+ text += "%s: %s\n" % (key, repr(val))
except:
pass
diff --git a/src/Hooks/dumpoops.cpp b/src/Hooks/dumpoops.cpp
index 4b6778d..01e65c4 100644
--- a/src/Hooks/dumpoops.cpp
+++ b/src/Hooks/dumpoops.cpp
@@ -83,6 +83,7 @@ int main(int argc, char **argv)
void *handle;
errno = 0;
+//TODO: use it directly, not via dlopen?
handle = dlopen(PLUGINS_LIB_DIR"/libKerneloopsScanner.so", RTLD_NOW);
if (!handle)
perror_msg_and_die("can't load %s", PLUGINS_LIB_DIR"/libKerneloopsScanner.so");
diff --git a/src/Hooks/hooklib.cpp b/src/Hooks/hooklib.cpp
new file mode 100644
index 0000000..41b9627
--- /dev/null
+++ b/src/Hooks/hooklib.cpp
@@ -0,0 +1,116 @@
+/*
+ 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 "hooklib.h"
+#include "DebugDump.h"
+#include <sys/statvfs.h>
+
+using namespace std;
+
+void parse_conf(const char *additional_conf, unsigned *setting_MaxCrashReportsSize, bool *setting_MakeCompatCore)
+{
+ FILE *fp = fopen(CONF_DIR"/abrt.conf", "r");
+ if (!fp)
+ return;
+
+ char line[256];
+ while (1)
+ {
+ if (fgets(line, sizeof(line), fp) == NULL)
+ {
+ fclose(fp);
+ if (additional_conf)
+ {
+ /* Next .conf file plz */
+ fp = fopen(additional_conf, "r");
+ if (fp)
+ {
+ additional_conf = NULL;
+ continue;
+ }
+ }
+ break;
+ }
+
+ unsigned len = strlen(line);
+ if (len > 0 && line[len-1] == '\n')
+ line[--len] = '\0';
+ const char *p = skip_whitespace(line);
+#undef DIRECTIVE
+#define DIRECTIVE "MaxCrashReportsSize"
+ if (setting_MaxCrashReportsSize && strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
+ {
+ p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
+ if (*p != '=')
+ continue;
+ p = skip_whitespace(p + 1);
+ if (isdigit(*p))
+ {
+ /* x1.25: go a bit up, so that usual in-daemon trimming
+ * kicks in first, and we don't "fight" with it. */
+ *setting_MaxCrashReportsSize = (unsigned long)xatou(p) * 5 / 4;
+ }
+ continue;
+ }
+#undef DIRECTIVE
+#define DIRECTIVE "MakeCompatCore"
+ if (setting_MakeCompatCore && strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)
+ {
+ p = skip_whitespace(p + sizeof(DIRECTIVE)-1);
+ if (*p != '=')
+ continue;
+ p = skip_whitespace(p + 1);
+ *setting_MakeCompatCore = string_to_bool(p);
+ continue;
+ }
+#undef DIRECTIVE
+ /* add more 'if (strncmp(p, DIRECTIVE, sizeof(DIRECTIVE)-1) == 0)' here... */
+ }
+}
+
+void check_free_space(unsigned setting_MaxCrashReportsSize)
+{
+ /* Check that at least MaxCrashReportsSize/4 MBs are free. */
+ struct statvfs vfs;
+ if (statvfs(DEBUG_DUMPS_DIR, &vfs) != 0
+ || (vfs.f_bfree / (1024*1024 / 4)) * vfs.f_bsize < setting_MaxCrashReportsSize
+ ) {
+ error_msg_and_die("Low free disk space detected, aborting dump");
+ }
+}
+
+/* rhbz#539551: "abrt going crazy when crashing process is respawned".
+ * Check total size of dump dir, if it overflows,
+ * delete oldest/biggest dumps.
+ */
+void trim_debug_dumps(unsigned setting_MaxCrashReportsSize, const char *exclude_path)
+{
+ int count = 10;
+ string worst_dir;
+ while (--count >= 0)
+ {
+ const char *base_dirname = strrchr(exclude_path, '/') + 1; /* never NULL */
+ /* We exclude our own dump from candidates for deletion (3rd param): */
+ double dirsize = get_dirsize_find_largest_dir(DEBUG_DUMPS_DIR, &worst_dir, base_dirname);
+ if (dirsize / (1024*1024) < setting_MaxCrashReportsSize || worst_dir == "")
+ break;
+ log("size of '%s' >= %u MB, deleting '%s'", DEBUG_DUMPS_DIR, setting_MaxCrashReportsSize, worst_dir.c_str());
+ delete_debug_dump_dir(concat_path_file(DEBUG_DUMPS_DIR, worst_dir.c_str()).c_str());
+ worst_dir = "";
+ }
+}
diff --git a/src/Hooks/hooklib.h b/src/Hooks/hooklib.h
new file mode 100644
index 0000000..0794ff6
--- /dev/null
+++ b/src/Hooks/hooklib.h
@@ -0,0 +1,21 @@
+/*
+ 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.
+*/
+
+void parse_conf(const char *additional_conf, unsigned *setting_MaxCrashReportsSize, bool *setting_MakeCompatCore);
+void check_free_space(unsigned setting_MaxCrashReportsSize);
+void trim_debug_dumps(unsigned setting_MaxCrashReportsSize, const char *exclude_path);