diff options
Diffstat (limited to 'src')
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); |
