diff options
| author | Karel Klic <kklic@redhat.com> | 2010-01-18 13:19:54 +0100 |
|---|---|---|
| committer | Karel Klic <kklic@redhat.com> | 2010-01-18 13:19:54 +0100 |
| commit | 4267cbcc29781ddcac00e259dfe05f3a26fbc2ec (patch) | |
| tree | 213e47138967f1e7af4ee9ff9a3f2ed861cb5815 | |
| parent | b2d1bd9e4f387c5a014d3002d741f25421c37aac (diff) | |
| parent | b41833ed61f7b579d2a46b26d261616c21a6ae32 (diff) | |
| download | abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.tar.gz abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.tar.xz abrt-4267cbcc29781ddcac00e259dfe05f3a26fbc2ec.zip | |
Merge branch 'master' of git://git.fedorahosted.org/git/abrt
80 files changed, 2106 insertions, 1133 deletions
@@ -16,13 +16,12 @@ BuildRequires: curl-devel BuildRequires: rpm-devel >= 4.6 BuildRequires: sqlite-devel > 3.0 BuildRequires: desktop-file-utils -BuildRequires: nss-devel +#BuildRequires: nss-devel BuildRequires: libnotify-devel BuildRequires: xmlrpc-c-devel BuildRequires: file-devel BuildRequires: python-devel BuildRequires: gettext -BuildRequires: nss-devel BuildRequires: polkit-devel BuildRequires: libzip-devel, libtar-devel, bzip2-devel, zlib-devel BuildRequires: intltool @@ -250,6 +249,7 @@ rm -rf $RPM_BUILD_ROOT %pre getent group abrt >/dev/null || groupadd -f --system abrt +getent passwd abrt >/dev/null || useradd --system -g abrt -d /etc/abrt -s /sbin/nologin abrt exit 0 %post @@ -279,7 +279,7 @@ fi %config(noreplace) %{_sysconfdir}/%{name}/%{name}.conf %config(noreplace) %{_sysconfdir}/dbus-1/system.d/dbus-%{name}.conf %{_initrddir}/%{name}d -%dir %attr(0775, root, abrt) %{_localstatedir}/cache/%{name} +%dir %attr(0755, abrt, abrt) %{_localstatedir}/cache/%{name} %dir /var/run/%{name} %dir %{_sysconfdir}/%{name} %dir %{_sysconfdir}/%{name}/plugins @@ -386,10 +386,12 @@ fi %files addon-python %defattr(-,root,root,-) -%attr(2755, root, abrt) %{_libexecdir}/abrt-hook-python +%config(noreplace) %{_sysconfdir}/%{name}/plugins/Python.conf +%attr(4755, abrt, abrt) %{_libexecdir}/abrt-hook-python %{_libdir}/%{name}/libPython.so* %{python_site}/*.py* + %files cli %defattr(-,root,root,-) %{_bindir}/abrt-cli diff --git a/configure.ac b/configure.ac index 5c10a3f..4f73d07 100644 --- a/configure.ac +++ b/configure.ac @@ -39,7 +39,7 @@ PKG_CHECK_MODULES([DBUS], [dbus-1]) PKG_CHECK_MODULES([RPM], [rpm]) PKG_CHECK_MODULES([CURL], [libcurl]) PKG_CHECK_MODULES([LIBNOTIFY], [libnotify]) -PKG_CHECK_MODULES([NSS], [nss]) +#PKG_CHECK_MODULES([NSS], [nss]) PKG_CHECK_MODULES([XMLRPC], [xmlrpc]) PKG_CHECK_MODULES([XMLRPC_CLIENT], [xmlrpc_client]) PKG_CHECK_MODULES([POLKIT],[polkit-gobject-1]) diff --git a/inc/abrtlib.h b/inc/abrtlib.h index 28140d8..ed54b52 100644 --- a/inc/abrtlib.h +++ b/inc/abrtlib.h @@ -132,6 +132,7 @@ int xsocket(int domain, int type, int protocol); void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen); void xlisten(int s, int backlog); ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, socklen_t tolen); +void xchdir(const char *path); void xstat(const char *name, struct stat *stat_buf); /* Just testing dent->d_type == DT_REG is wrong: some filesystems * do not report the type, they report DT_UNKNOWN for every dirent @@ -156,11 +157,35 @@ void xunlink(const char *pathname); off_t copyfd_eof(int src_fd, int dst_fd); off_t copyfd_size(int src_fd, int dst_fd, off_t size); void copyfd_exact_size(int src_fd, int dst_fd, off_t size); -off_t copy_file(const char *src_name, const char *dst_name); +off_t copy_file(const char *src_name, const char *dst_name, int mode); void xsetreuid(uid_t ruid, uid_t euid); -void xsetregid(gid_t rgid, uid_t egid); +void xsetregid(gid_t rgid, gid_t egid); +enum { + EXECFLG_INPUT = 1 << 0, + EXECFLG_OUTPUT = 1 << 1, + EXECFLG_INPUT_NUL = 1 << 2, + EXECFLG_OUTPUT_NUL = 1 << 3, + EXECFLG_ERR2OUT = 1 << 4, + EXECFLG_ERR_NUL = 1 << 5, + EXECFLG_QUIET = 1 << 6, + EXECFLG_SETGUID = 1 << 7, + EXECFLG_SETSID = 1 << 8, +}; +/* Returns pid */ +pid_t fork_execv_on_steroids(int flags, + char **argv, + int *pipefds, + char **unsetenv_vec, + const char *dir, + uid_t uid); +/* Returns malloc'ed string. NULs are retained, and extra one is appended + * after the last byte (this NUL is not accounted for in *size_p) */ +char *run_in_shell_and_save_output(int flags, + const char *cmd, + const char *dir, + size_t *size_p); unsigned long long monotonic_ns(void); @@ -246,7 +271,6 @@ to_string(T x) return o.str(); } -std::string popen_and_save_output(const char *cmd); void parse_args(const char *psArgs, vector_string_t& pArgs, int quote = -1); void parse_release(const char *pRelease, std::string& pProduct, std::string& pVersion); diff --git a/lib/Plugins/Bugzilla.cpp b/lib/Plugins/Bugzilla.cpp index 2d065f6..6f0f8d7 100644 --- a/lib/Plugins/Bugzilla.cpp +++ b/lib/Plugins/Bugzilla.cpp @@ -13,6 +13,9 @@ #define XML_RPC_SUFFIX "/xmlrpc.cgi" +/* + * TODO: npajkovs: better deallocation of xmlrpc value + */ /* * Static namespace for xmlrpc stuff. @@ -39,7 +42,8 @@ void ctx::login(const char* login, const char* passwd) xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s})", "login", login, "password", passwd); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.login", param, &result); @@ -62,14 +66,16 @@ void ctx::logout() xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", ""); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "User.logout", param, &result); xmlrpc_DECREF(param); if (result) xmlrpc_DECREF(result); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); } bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) @@ -77,23 +83,36 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) xmlrpc_env env; xmlrpc_env_init(&env); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "(s)", to_string(bug_id).c_str()); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.getBug", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* reporter_member = NULL; xmlrpc_struct_find_value(&env, result, "reporter", &reporter_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (reporter_member) { const char* reporter = NULL; xmlrpc_read_string(&env, reporter_member, &reporter); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(reporter_member); + throw_xml_fault(&env); + } bool eq = (strcmp(reporter, login) == 0); free((void*)reporter); @@ -107,7 +126,11 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) xmlrpc_value* cc_member = NULL; xmlrpc_struct_find_value(&env, result, "cc", &cc_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (cc_member) { @@ -117,11 +140,22 @@ bool ctx::check_cc_and_reporter(uint32_t bug_id, const char* login) { xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, cc_member, i, &item); // Correct - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(cc_member); + throw_xml_fault(&env); + } const char* cc = NULL; xmlrpc_read_string(&env, item, &cc); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(cc_member); + xmlrpc_DECREF(item); + throw_xml_fault(&env); + } bool eq = (strcmp(cc, login) == 0); free((void*)cc); @@ -145,15 +179,19 @@ void ctx::add_plus_one_cc(uint32_t bug_id, const char* login) xmlrpc_env env; xmlrpc_env_init(&env); - xmlrpc_value* param = xmlrpc_build_value(&env, "({s:i,s:{s:(s)}})", "ids", bug_id, "updates", "add_cc", login); - throw_if_xml_fault_occurred(&env); + // fails only when you write query. when it's done it never fails. + xmlrpc_value* param = xmlrpc_build_value(&env, "({s:i,s:{s:(s)}})", "ids", bug_id, "updates", "add_cc", login); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.update", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) + xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_DECREF(result); - xmlrpc_DECREF(param); } int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID) @@ -163,36 +201,61 @@ int32_t ctx::check_uuid_in_bugzilla(const char* component, const char* UUID) std::string query = ssprintf("ALL component:\"%s\" statuswhiteboard:\"%s\"", component, UUID); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s})", "quicksearch", query.c_str()); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.search", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* bugs_member = NULL; xmlrpc_struct_find_value(&env, result, "bugs", &bugs_member); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } if (bugs_member) { // when array size is equal 0 that means no bug reported uint32_t array_size = xmlrpc_array_size(&env, bugs_member); - throw_if_xml_fault_occurred(&env); - if (array_size == 0) + if (env.fault_occurred) { + xmlrpc_DECREF(result); xmlrpc_DECREF(bugs_member); + throw_xml_fault(&env); + } + else if (array_size == 0) + { xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); return -1; } xmlrpc_value* item = NULL; xmlrpc_array_read_item(&env, bugs_member, 0, &item); // Correct - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); + throw_xml_fault(&env); + } + xmlrpc_value* bug = NULL; xmlrpc_struct_find_value(&env, item, "bug_id", &bug); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(bugs_member); + xmlrpc_DECREF(item); + throw_xml_fault(&env); + } if (bug) { @@ -236,6 +299,7 @@ uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport) std::string version; parse_release(release.c_str(), product, version); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "({s:s,s:s,s:s,s:s,s:s,s:s,s:s})", "product", product.c_str(), "component", component.c_str(), @@ -245,27 +309,39 @@ uint32_t ctx::new_bug(const map_crash_report_t& pCrashReport) "status_whiteboard", status_whiteboard.c_str(), "platform", arch.c_str() ); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Bug.create", param, &result); - throw_if_xml_fault_occurred(&env); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) + xmlrpc_DECREF(param); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* id; xmlrpc_struct_find_value(&env, result, "id", &id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } xmlrpc_int bug_id = -1; if (id) { xmlrpc_read_int(&env, id, &bug_id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + xmlrpc_DECREF(id); + throw_xml_fault(&env); + } log("New bug id: %i", bug_id); update_client(_("New bug id: %i"), bug_id); } xmlrpc_DECREF(result); - xmlrpc_DECREF(param); xmlrpc_DECREF(id); return bug_id; } @@ -287,6 +363,7 @@ void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCra if (type == CD_ATT) { char *encoded64 = encode_base64(content.c_str(), content.length()); + // fails only when you write query. when it's done it never fails. xmlrpc_value* param = xmlrpc_build_value(&env, "(s{s:s,s:s,s:s,s:s})", bug_id_str, "description", ("File: " + filename).c_str(), @@ -295,12 +372,18 @@ void ctx::add_attachments(const char* bug_id_str, const map_crash_report_t& pCra "data", encoded64 ); free(encoded64); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "bugzilla.addAttachment", param, &result); - throw_if_xml_fault_occurred(&env); - xmlrpc_DECREF(result); + // we don't need anymore xml structure for calling xmlrpc query(calls only once) xmlrpc_DECREF(param); + if (env.fault_occurred) + { + xmlrpc_DECREF(result); + throw_xml_fault(&env); + } + xmlrpc_DECREF(result); } } } diff --git a/lib/Plugins/CCpp.conf b/lib/Plugins/CCpp.conf index dfdbec8..153efb9 100644 --- a/lib/Plugins/CCpp.conf +++ b/lib/Plugins/CCpp.conf @@ -1,4 +1,5 @@ # Configuration file for CCpp hook and plugin +Enabled = yes # If you also want to dump file named "core" # in crashed process' current dir, set to "yes" diff --git a/lib/Plugins/CCpp.cpp b/lib/Plugins/CCpp.cpp index 1a01c01..e0db9cf 100644 --- a/lib/Plugins/CCpp.cpp +++ b/lib/Plugins/CCpp.cpp @@ -24,9 +24,8 @@ #include <sstream> #include <set> #include <iomanip> -#include <nss.h> -#include <sechash.h> -#include <sysexits.h> +//#include <nss.h> +//#include <sechash.h> #include "abrtlib.h" #include "CCpp.h" #include "ABRTException.h" @@ -34,6 +33,8 @@ #include "CommLayerInner.h" #include "Polkit.h" +#include "CCpp_sha1.h" + using namespace std; #define CORE_PATTERN_IFACE "/proc/sys/kernel/core_pattern" @@ -54,11 +55,13 @@ CAnalyzerCCpp::CAnalyzerCCpp() : static string CreateHash(const char *pInput) { - string ret; - HASHContext* hc; - unsigned char hash[SHA1_LENGTH]; unsigned int len; +#if 0 +{ + char hash_str[SHA1_LENGTH*2 + 1]; + unsigned char hash[SHA1_LENGTH]; + HASHContext *hc; hc = HASH_Create(HASH_AlgSHA1); if (!hc) { @@ -69,7 +72,6 @@ static string CreateHash(const char *pInput) HASH_End(hc, hash, &len, sizeof(hash)); HASH_Destroy(hc); - char hash_str[SHA1_LENGTH*2 + 1]; char *d = hash_str; unsigned char *s = hash; while (len) @@ -80,6 +82,29 @@ static string CreateHash(const char *pInput) len--; } *d = '\0'; +//log("hash1:%s str:'%s'", hash_str, pInput); +} +#endif + + char hash_str[SHA1_RESULT_LEN*2 + 1]; + unsigned char hash2[SHA1_RESULT_LEN]; + sha1_ctx_t sha1ctx; + sha1_begin(&sha1ctx); + sha1_hash(pInput, strlen(pInput), &sha1ctx); + sha1_end(hash2, &sha1ctx); + len = SHA1_RESULT_LEN; + + char *d = hash_str; + unsigned char *s = hash2; + while (len) + { + *d++ = "0123456789abcdef"[*s >> 4]; + *d++ = "0123456789abcdef"[*s & 0xf]; + s++; + len--; + } + *d = '\0'; +//log("hash2:%s str:'%s'", hash_str, pInput); return hash_str; } @@ -99,54 +124,28 @@ static string concat_str_vector(char **strings) /* Returns status. See `man 2 wait` for status information. */ static int ExecVP(char **pArgs, uid_t uid, int redirect_stderr, string& pOutput) { - int pipeout[2]; - pid_t child; - - xpipe(pipeout); - child = fork(); - if (child == -1) - { - perror_msg_and_die("fork"); - } - if (child == 0) - { - VERB1 log("Executing: %s", concat_str_vector(pArgs).c_str()); - close(pipeout[0]); /* read side of the pipe */ - xmove_fd(pipeout[1], STDOUT_FILENO); - /* Make sure stdin is safely open to nothing */ - xmove_fd(xopen("/dev/null", O_RDONLY), STDIN_FILENO); - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - setsid(); - - /* Nuke everything which may make setlocale() switch to non-POSIX locale: - * we need to avoid having gdb output in some obscure language. - */ - unsetenv("LANG"); - unsetenv("LC_ALL"); - unsetenv("LC_COLLATE"); - unsetenv("LC_CTYPE"); - unsetenv("LC_MESSAGES"); - unsetenv("LC_MONETARY"); - unsetenv("LC_NUMERIC"); - unsetenv("LC_TIME"); - - if (redirect_stderr) - { - /* We want parent to see errors in the same stream */ - xdup2(STDOUT_FILENO, STDERR_FILENO); - } - execvp(pArgs[0], pArgs); - /* VERB1 since sometimes we expect errors here */ - VERB1 perror_msg("Can't execute '%s'", pArgs[0]); - exit(1); - } + /* Nuke everything which may make setlocale() switch to non-POSIX locale: + * we need to avoid having gdb output in some obscure language. + */ + static const char *const unsetenv_vec[] = { + "LANG", + "LC_ALL", + "LC_COLLATE", + "LC_CTYPE", + "LC_MESSAGES", + "LC_MONETARY", + "LC_NUMERIC", + "LC_TIME", + NULL + }; + + int flags = EXECFLG_INPUT_NUL | EXECFLG_OUTPUT | EXECFLG_SETGUID | EXECFLG_SETSID | EXECFLG_QUIET; + if (redirect_stderr) + flags |= EXECFLG_ERR2OUT; + VERB1 flags &= ~EXECFLG_QUIET; - close(pipeout[1]); /* write side of the pipe */ + int pipeout[2]; + pid_t child = fork_execv_on_steroids(flags, pArgs, pipeout, (char**)unsetenv_vec, /*dir:*/ NULL, uid); int r; char buff[1024]; @@ -155,8 +154,8 @@ static int ExecVP(char **pArgs, uid_t uid, int redirect_stderr, string& pOutput) buff[r] = '\0'; pOutput += buff; } - close(pipeout[0]); + int status; waitpid(child, &status, 0); /* prevent having zombie child process */ @@ -379,6 +378,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, int pipeout[2]; //TODO: can we use ExecVP? xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -394,7 +394,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir); /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); + char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu", (long)getpid(), (long)time(NULL)); /* log() goes to stderr/syslog, it's ok to use it here */ VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, debuginfo_dirs); /* We want parent to see errors in the same stream */ @@ -545,6 +545,8 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) { log(_("Getting global universal unique identification...")); +//TODO: convert to fork_execv_on_steroids(), nuke static concat_str_vector + string backtrace_path = concat_path_file(pDebugDumpDir, FILENAME_BACKTRACE); string executable; string package; @@ -574,6 +576,8 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) int pipeout[2]; xpipe(pipeout); /* stdout of abrt-backtrace */ + + fflush(NULL); pid_t child = fork(); if (child == -1) perror_msg_and_die("fork"); @@ -617,13 +621,29 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) { perror_msg("abrt-backtrace not executed properly, " "status: %x signal: %d", status, WIFSIGNALED(status)); - } else + } + else { int exit_status = WEXITSTATUS(status); - if (exit_status != 0) + if (exit_status == 79) /* EX_PARSINGFAILED */ { + /* abrt-backtrace returns alternative backtrace + representation in this case, so everything will work + as expected except worse duplication detection */ + log_msg("abrt-backtrace failed to parse the backtrace"); + } + else if (exit_status == 80) /* EX_THREADDETECTIONFAILED */ + { + /* abrt-backtrace returns backtrace with all threads + in this case, so everything will work as expected + except worse duplication detection */ + log_msg("abrt-backtrace failed to determine crash frame"); + } + else if (exit_status != 0) + { + /* this is unexpected problem and it should be investigated */ error_msg("abrt-backtrace run failed, exit value: %d", - exit_status); + exit_status); } } @@ -635,8 +655,9 @@ string CAnalyzerCCpp::GetGlobalUUID(const char *pDebugDumpDir) return CreateHash(hash_base.c_str()); } -static bool DebuginfoCheckPolkit(int uid) +static bool DebuginfoCheckPolkit(uid_t uid) { + fflush(NULL); int child_pid = fork(); if (child_pid < 0) { @@ -653,8 +674,10 @@ static bool DebuginfoCheckPolkit(int uid) //parent int status; - if (waitpid(child_pid, &status, 0) > 0 && WEXITSTATUS(status) == 0) - { + if (waitpid(child_pid, &status, 0) > 0 + && WIFEXITED(status) + && WEXITSTATUS(status) == 0 + ) { return true; //authorization OK } log("UID %d is not authorized to install debuginfos", uid); diff --git a/lib/Plugins/CCpp_sha1.cpp b/lib/Plugins/CCpp_sha1.cpp new file mode 100644 index 0000000..86a9e83 --- /dev/null +++ b/lib/Plugins/CCpp_sha1.cpp @@ -0,0 +1,214 @@ +/* vi: set sw=4 ts=4: */ +/* + * Based on shasum from http://www.netsw.org/crypto/hash/ + * Majorly hacked up to use Dr Brian Gladman's sha1 code + * + * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * --------------------------------------------------------------------------- + * Issue Date: 10/11/2002 + * + * This is a byte oriented version of SHA1 that operates on arrays of bytes + * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * + * --------------------------------------------------------------------------- + */ +#include "abrtlib.h" +#include "CCpp_sha1.h" + +#if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ +# define SHA1_BIG_ENDIAN 1 +# define SHA1_LITTLE_ENDIAN 0 +#elif __BYTE_ORDER == __BIG_ENDIAN +# define SHA1_BIG_ENDIAN 1 +# define SHA1_LITTLE_ENDIAN 0 +#elif __BYTE_ORDER == __LITTLE_ENDIAN +# define SHA1_BIG_ENDIAN 0 +# define SHA1_LITTLE_ENDIAN 1 +#else +# error "Can't determine endianness" +#endif + + +#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) +#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) +/* for sha512: */ +#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) +#if SHA1_LITTLE_ENDIAN +static inline uint64_t hton64(uint64_t v) +{ + return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); +} +#else +#define hton64(v) (v) +#endif +#define ntoh64(v) hton64(v) + +/* To check alignment gcc has an appropriate operator. Other + compilers don't. */ +#if defined(__GNUC__) && __GNUC__ >= 2 +# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0) +#else +# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0) +#endif + + +/* Some arch headers have conflicting defines */ +#undef ch +#undef parity +#undef maj +#undef rnd + +static void sha1_process_block64(sha1_ctx_t *ctx) +{ + unsigned t; + uint32_t W[80], a, b, c, d, e; + const uint32_t *words = (uint32_t*) ctx->wbuffer; + + for (t = 0; t < 16; ++t) { + W[t] = ntohl(*words); + words++; + } + + for (/*t = 16*/; t < 80; ++t) { + uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; + W[t] = rotl32(T, 1); + } + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + +/* Reverse byte order in 32-bit words */ +#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) +#define parity(x,y,z) ((x) ^ (y) ^ (z)) +#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) +/* A normal version as set out in the FIPS. This version uses */ +/* partial loop unrolling and is optimised for the Pentium 4 */ +#define rnd(f,k) \ + do { \ + uint32_t T = a; \ + a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ + e = d; \ + d = c; \ + c = rotl32(b, 30); \ + b = T; \ + } while (0) + + for (t = 0; t < 20; ++t) + rnd(ch, 0x5a827999); + + for (/*t = 20*/; t < 40; ++t) + rnd(parity, 0x6ed9eba1); + + for (/*t = 40*/; t < 60; ++t) + rnd(maj, 0x8f1bbcdc); + + for (/*t = 60*/; t < 80; ++t) + rnd(parity, 0xca62c1d6); +#undef ch +#undef parity +#undef maj +#undef rnd + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; +} + +void sha1_begin(sha1_ctx_t *ctx) +{ + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; + ctx->total64 = 0; + ctx->process_block = sha1_process_block64; +} + +static const uint32_t init256[] = { + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 +}; +static const uint32_t init512_lo[] = { + 0xf3bcc908, + 0x84caa73b, + 0xfe94f82b, + 0x5f1d36f1, + 0xade682d1, + 0x2b3e6c1f, + 0xfb41bd6b, + 0x137e2179 +}; + +/* Used also for sha256 */ +void sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx) +{ + unsigned in_buf = ctx->total64 & 63; + unsigned add = 64 - in_buf; + + ctx->total64 += len; + + while (len >= add) { /* transfer whole blocks while possible */ + memcpy(ctx->wbuffer + in_buf, buffer, add); + buffer = (const char *)buffer + add; + len -= add; + add = 64; + in_buf = 0; + ctx->process_block(ctx); + } + + memcpy(ctx->wbuffer + in_buf, buffer, len); +} + +/* Used also for sha256 */ +void sha1_end(void *resbuf, sha1_ctx_t *ctx) +{ + unsigned pad, in_buf; + + in_buf = ctx->total64 & 63; + /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ + ctx->wbuffer[in_buf++] = 0x80; + + /* This loop iterates either once or twice, no more, no less */ + while (1) { + pad = 64 - in_buf; + memset(ctx->wbuffer + in_buf, 0, pad); + in_buf = 0; + /* Do we have enough space for the length count? */ + if (pad >= 8) { + /* Store the 64-bit counter of bits in the buffer in BE format */ + uint64_t t = ctx->total64 << 3; + t = hton64(t); + /* wbuffer is suitably aligned for this */ + *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; + } + ctx->process_block(ctx); + if (pad >= 8) + break; + } + + in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8; + /* This way we do not impose alignment constraints on resbuf: */ + if (SHA1_LITTLE_ENDIAN) { + unsigned i; + for (i = 0; i < in_buf; ++i) + ctx->hash[i] = htonl(ctx->hash[i]); + } + memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf); +} diff --git a/lib/Plugins/CCpp_sha1.h b/lib/Plugins/CCpp_sha1.h new file mode 100644 index 0000000..abadfd9 --- /dev/null +++ b/lib/Plugins/CCpp_sha1.h @@ -0,0 +1,32 @@ +/* vi: set sw=4 ts=4: */ +/* + * Based on shasum from http://www.netsw.org/crypto/hash/ + * Majorly hacked up to use Dr Brian Gladman's sha1 code + * + * Copyright (C) 2002 Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK. + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * + * --------------------------------------------------------------------------- + * Issue Date: 10/11/2002 + * + * This is a byte oriented version of SHA1 that operates on arrays of bytes + * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * + * --------------------------------------------------------------------------- + */ + +#define SHA1_RESULT_LEN (5 * 4) + +typedef struct sha1_ctx_t { + uint32_t hash[8]; /* 5, +3 elements for sha256 */ + uint64_t total64; + uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */ + void (*process_block)(struct sha1_ctx_t*); +} sha1_ctx_t; + +void sha1_begin(sha1_ctx_t *ctx); +void sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx); +void sha1_end(void *resbuf, sha1_ctx_t *ctx); diff --git a/lib/Plugins/Catcut.conf b/lib/Plugins/Catcut.conf index 456d7f8..a0249fd 100644 --- a/lib/Plugins/Catcut.conf +++ b/lib/Plugins/Catcut.conf @@ -1,3 +1,4 @@ +Enabled=1 # Catcut URL CatcutURL = http://127.0.0.1:8080/catcut/xmlrpc # yes means that ssl certificates will not be checked @@ -6,3 +7,4 @@ NoSSLVerify = no Login = gavin # your password Password = junk +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Catcut.cpp b/lib/Plugins/Catcut.cpp index a56015d..27b868d 100644 --- a/lib/Plugins/Catcut.cpp +++ b/lib/Plugins/Catcut.cpp @@ -13,7 +13,7 @@ using namespace std; static int -put_stream(const char *pURL, FILE* f, size_t content_length) +put_stream(const char *pURL, FILE* f, off_t content_length) { CURL* curl = xcurl_easy_init(); /* enable uploading */ @@ -22,8 +22,8 @@ put_stream(const char *pURL, FILE* f, size_t content_length) curl_easy_setopt(curl, CURLOPT_URL, pURL); /* file handle: passed to the default callback, it will fread() it */ curl_easy_setopt(curl, CURLOPT_READDATA, f); - /* get file size */ - curl_easy_setopt(curl, CURLOPT_INFILESIZE, content_length); + /* file size */ + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)content_length); /* everything is done here; result 0 means success */ int result = curl_easy_perform(curl); /* goodbye */ @@ -43,9 +43,9 @@ send_string(const char *pURL, return; } + size_t content_length = strlen(pContent); while (1) { - int content_length = strlen(pContent); FILE* f = fmemopen((void*)pContent, content_length, "r"); if (!f) { @@ -53,7 +53,7 @@ send_string(const char *pURL, } int result = put_stream(pURL, f, content_length); fclose(f); - if (!result) + if (result == 0) return; update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result)); if (--retryCount <= 0) @@ -88,10 +88,9 @@ send_file(const char *pURL, } struct stat buf; fstat(fileno(f), &buf); /* can't fail */ - int content_length = buf.st_size; - int result = put_stream(pURL, f, content_length); + int result = put_stream(pURL, f, buf.st_size); fclose(f); - if (!result) + if (result == 0) return; update_client(_("Sending failed, try it again: %s"), curl_easy_strerror((CURLcode)result)); if (--retryCount <= 0) @@ -122,6 +121,7 @@ resolve_relative_url(const char *url, const char *base) } const char *end_of_protocol = strchr(base, ':'); +//TODO: why is this safe?!! string protocol(base, end_of_protocol - base); end_of_protocol += 3; /* skip "://" */ @@ -167,11 +167,14 @@ struct_find_int(xmlrpc_env* env, xmlrpc_value* result, { xmlrpc_value* an_xmlrpc_value; xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); + if (an_xmlrpc_value) { xmlrpc_read_int(env, an_xmlrpc_value, &value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); xmlrpc_DECREF(an_xmlrpc_value); return true; } @@ -184,12 +187,14 @@ struct_find_string(xmlrpc_env* env, xmlrpc_value* result, { xmlrpc_value* an_xmlrpc_value; xmlrpc_struct_find_value(env, result, fieldName, &an_xmlrpc_value); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); if (an_xmlrpc_value) { const char* value_s; xmlrpc_read_string(env, an_xmlrpc_value, &value_s); - throw_if_xml_fault_occurred(env); + if (env->fault_occurred) + throw_xml_fault(env); value = value_s; xmlrpc_DECREF(an_xmlrpc_value); free((void*)value_s); @@ -228,20 +233,24 @@ ctx::login(const char* login, const char* passwd) xmlrpc_env_init(&env); xmlrpc_value* param = xmlrpc_build_value(&env, "(ss)", login, passwd); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.auth", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *cookie_xml; const char *cookie; string cookie_str; xmlrpc_struct_find_value(&env, result, "cookie", &cookie_xml); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_read_string(&env, cookie_xml, &cookie); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); cookie_str = cookie; /* xmlrpc_read_string returns *malloc'ed ptr*. * doc is not very clear on it, but I looked in xmlrpc sources. */ @@ -284,20 +293,24 @@ ctx::new_bug(const char *auth_cookie, const map_crash_report_t& pCrashReport) "status_whiteboard", status_whiteboard.c_str(), "platform", arch.c_str() ); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *result; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.createTicket", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value *bug_id_xml; const char *bug_id; string bug_id_str; xmlrpc_struct_find_value(&env, result, "ticket", &bug_id_xml); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_read_string(&env, bug_id_xml, &bug_id); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); bug_id_str = bug_id; log("New bug id: %s", bug_id); update_client(_("New bug id: %s"), bug_id); @@ -321,12 +334,14 @@ ctx::request_upload(const char* auth_cookie, const char* pTicketName, pTicketName, fileName, description); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); xmlrpc_value* result = NULL; xmlrpc_client_call2(&env, m_pClient, m_pServer_info, "Catcut.requestUpload", param, &result); xmlrpc_DECREF(param); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); string URL; bool has_URL = struct_find_string(&env, result, "uri", URL); diff --git a/lib/Plugins/FileTransfer.conf b/lib/Plugins/FileTransfer.conf index 75e5671..c92eaee 100644 --- a/lib/Plugins/FileTransfer.conf +++ b/lib/Plugins/FileTransfer.conf @@ -17,3 +17,4 @@ RetryCount = 3 #how long we wait between we retry the upload (in seconds) RetryDelay = 20 +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/FileTransfer.cpp b/lib/Plugins/FileTransfer.cpp index 60e1e66..b08ecd5 100644 --- a/lib/Plugins/FileTransfer.cpp +++ b/lib/Plugins/FileTransfer.cpp @@ -80,11 +80,7 @@ void CFileTransfer::SendFile(const char *pURL, const char *pFilename) { throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename); } - if (fstat(fileno(f), &buf) == -1) - { - fclose(f); - throw CABRTException(EXCEP_PLUGIN, "Can't stat archive file '%s'", pFilename); - } + fstat(fileno(f), &buf); /* never fails */ curl = xcurl_easy_init(); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); @@ -92,7 +88,7 @@ void CFileTransfer::SendFile(const char *pURL, const char *pFilename) curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str()); /* FILE handle: passed to the default callback, it will fread() it */ curl_easy_setopt(curl, CURLOPT_READDATA, f); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size); /* everything is done here; result 0 means success */ int result = curl_easy_perform(curl); curl_easy_cleanup(curl); @@ -110,13 +106,11 @@ parameter "something" to each filename, now used in create_zip, but can be useful for some future archivers as well */ -static void traverse_directory(const char * directory, void * something, - void (*func)(void *, const char *) ) +static void traverse_directory(const char *directory, void *something, + void (*func)(void *, const char *)) { - DIR * dp; - struct dirent * dirp; - char complete_name[BUFSIZ]; - char * end; + DIR *dp; + struct dirent *dirp; dp = opendir(directory); if (dp == NULL) @@ -127,14 +121,8 @@ static void traverse_directory(const char * directory, void * something, { if (is_regular_file(dirp, directory)) { - end = stpcpy(complete_name, directory); - if (end[-1] != '/') - { - *end++ = '/'; - } - end = stpcpy(end, dirp->d_name); - - func(something, complete_name); + string complete_name = concat_path_file(directory, dirp->d_name); + func(something, complete_name.c_str()); } } closedir(dp); @@ -189,6 +177,7 @@ static void create_targz(const char * archive_name, const char * directory) f = fopen(name_without_gz, "r"); if (f == NULL) { +//TODO: we leak uncompressed tar file on disk?? free(name_without_gz); return; } @@ -234,6 +223,7 @@ static void create_tarbz2(const char * archive_name, const char * directory) f = fopen(archive_name, "w"); if (f == NULL) { +//TODO: we leak uncompressed tar file on disk?? close(tarFD); free(name_without_bz2); return; @@ -320,6 +310,7 @@ void CFileTransfer::Run(const char *pActionDir, const char *pArgs) else if (strcmp(pArgs, "one") == 0) { /* just send one archive */ +//TODO: where are we creating it??!! In cwd, which may well be / ??!!! string archivename = ssprintf("%s-%s%s", hostname, DirBase(pActionDir).c_str(), m_sArchiveType.c_str()); try { diff --git a/lib/Plugins/Firefox.cpp b/lib/Plugins/Firefox.cpp index 92ef4e5..d980755 100644 --- a/lib/Plugins/Firefox.cpp +++ b/lib/Plugins/Firefox.cpp @@ -99,6 +99,8 @@ static pid_t ExecVP(char** pArgs, uid_t uid, std::string& pOutput) pid_t child; xpipe(pipeout); + + fflush(NULL); child = fork(); if (child == -1) { @@ -549,6 +551,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) xpipe(pipein); xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -673,6 +676,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) int pipeout[2]; //TODO: can we use ExecVP? xpipe(pipeout); + fflush(NULL); pid_t child = fork(); if (child < 0) { @@ -692,7 +696,7 @@ static void InstallDebugInfos(const char *pDebugDumpDir, std::string& build_ids) char *coredump = xasprintf("%s/"FILENAME_COREDUMP, pDebugDumpDir); /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%u-%lu", (int)getpid(), (long)time(NULL)); + char *tempdir = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu", (long)getpid(), (long)time(NULL)); /* log() goes to stderr/syslog, it's ok to use it here */ VERB1 log("Executing: %s %s %s %s", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR); execlp("abrt-debuginfo-install", "abrt-debuginfo-install", coredump, tempdir, DEBUGINFO_CACHE_DIR, NULL); @@ -839,8 +843,9 @@ std::string CAnalyzerFirefox::GetGlobalUUID(const char *pDebugDumpDir) return CreateHash(package + executable + independentBacktrace); } -static bool DebuginfoCheckPolkit(int uid) +static bool DebuginfoCheckPolkit(uid_t uid) { + fflush(NULL); int child_pid = fork(); if (child_pid < 0) { @@ -857,8 +862,10 @@ static bool DebuginfoCheckPolkit(int uid) //parent int status; - if (waitpid(child_pid, &status, 0) > 0 && WEXITSTATUS(status) == 0) - { + if (waitpid(child_pid, &status, 0) > 0 + && WIFEXITED(status) + && WEXITSTATUS(status) == 0 + ) { return true; //authorization OK } log("UID %d is not authorized to install debuginfos", uid); diff --git a/lib/Plugins/Kerneloops.conf b/lib/Plugins/Kerneloops.conf index 5623596..1db2436 100644 --- a/lib/Plugins/Kerneloops.conf +++ b/lib/Plugins/Kerneloops.conf @@ -15,3 +15,4 @@ SysLogFile = /var/log/messages # KerneloopsReporter configuration ################################## SubmitURL = http://submit.kerneloops.org/submitoops.php +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/KerneloopsScanner.cpp b/lib/Plugins/KerneloopsScanner.cpp index 128e083..1bb45ab 100644 --- a/lib/Plugins/KerneloopsScanner.cpp +++ b/lib/Plugins/KerneloopsScanner.cpp @@ -99,13 +99,14 @@ void CKerneloopsScanner::SaveOopsToDebugDump() *second_line++ = '\0'; try { - CDebugDump debugDump; - debugDump.Create(path, 0); - debugDump.SaveText(FILENAME_ANALYZER, "Kerneloops"); - debugDump.SaveText(FILENAME_EXECUTABLE, "kernel"); - debugDump.SaveText(FILENAME_KERNEL, first_line); - debugDump.SaveText(FILENAME_PACKAGE, "not_applicable"); - debugDump.SaveText(FILENAME_KERNELOOPS, second_line); + CDebugDump dd; + dd.Create(path, 0); + dd.SaveText(FILENAME_ANALYZER, "Kerneloops"); + dd.SaveText(FILENAME_EXECUTABLE, "kernel"); + dd.SaveText(FILENAME_KERNEL, first_line); + dd.SaveText(FILENAME_PACKAGE, "not_applicable"); + dd.SaveText(FILENAME_CMDLINE, "not_applicable"); + dd.SaveText(FILENAME_KERNELOOPS, second_line); } catch (CABRTException& e) { @@ -121,7 +122,7 @@ int CKerneloopsScanner::ScanDmesg() int cnt_FoundOopses; char *buffer; - int pagesz = getpagesize(); + long pagesz = sysconf(_SC_PAGESIZE); buffer = (char*)xzalloc(pagesz + 1); @@ -147,8 +148,10 @@ int CKerneloopsScanner::ScanSysLogFile(const char *filename) if (fd < 0) return 0; statb.st_size = 0; /* paranoia */ - if (fstat(fd, &statb) != 0 || statb.st_size < 1) + if (fstat(fd, &statb) != 0 || statb.st_size < 1) { + close(fd); return 0; + } /* * in theory there's a race here, since someone could spew diff --git a/lib/Plugins/Logger.conf b/lib/Plugins/Logger.conf index 901b3cf..39ba47e 100644 --- a/lib/Plugins/Logger.conf +++ b/lib/Plugins/Logger.conf @@ -2,4 +2,5 @@ LogPath = /var/log/abrt-logger -AppendLogs = yes
\ No newline at end of file +AppendLogs = yes +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Mailx.conf b/lib/Plugins/Mailx.conf index 44c1d18..de19709 100644 --- a/lib/Plugins/Mailx.conf +++ b/lib/Plugins/Mailx.conf @@ -13,3 +13,4 @@ EmailTo = root@localhost # Warning! enabling this may cause sending a lot of MB via email SendBinaryData = no +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/Mailx.cpp b/lib/Plugins/Mailx.cpp index 70eddb8..df33e84 100644 --- a/lib/Plugins/Mailx.cpp +++ b/lib/Plugins/Mailx.cpp @@ -39,33 +39,16 @@ CMailx::CMailx() : static void exec_and_feed_input(uid_t uid, const char* pText, char **pArgs) { int pipein[2]; - pid_t child; - xpipe(pipein); - child = fork(); - if (child == -1) - { - close(pipein[0]); - close(pipein[1]); - throw CABRTException(EXCEP_PLUGIN, "Can't fork"); - } - if (child == 0) - { - close(pipein[1]); - xmove_fd(pipein[0], STDIN_FILENO); - - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - setgroups(1, &gid); - xsetregid(gid, gid); - xsetreuid(uid, uid); - - execvp(pArgs[0], pArgs); - exit(1); /* exec failed */ - } + pid_t child = fork_execv_on_steroids( + EXECFLG_INPUT | EXECFLG_QUIET | EXECFLG_SETGUID, + pArgs, + pipein, + /*unsetenv_vec:*/ NULL, + /*dir:*/ NULL, + uid); - close(pipein[0]); - safe_write(pipein[1], pText, strlen(pText)); + full_write(pipein[1], pText, strlen(pText)); close(pipein[1]); waitpid(child, NULL, 0); /* wait for command completion */ diff --git a/lib/Plugins/Makefile.am b/lib/Plugins/Makefile.am index 2e5ee38..df35416 100644 --- a/lib/Plugins/Makefile.am +++ b/lib/Plugins/Makefile.am @@ -32,7 +32,8 @@ dist_pluginsconf_DATA = \ Bugzilla.conf \ Catcut.conf \ TicketUploader.conf \ - FileTransfer.conf + FileTransfer.conf \ + Python.conf man_MANS = abrt-FileTransfer.7 abrt-Bugzilla.7 abrt-KerneloopsReporter.7 \ abrt-KerneloopsScanner.7 abrt-Logger.7 abrt-Mailx.7 abrt-plugins.7 \ @@ -51,14 +52,13 @@ install-data-hook: $(DESTDIR)/$(DEBUG_INFO_DIR) $(DESTDIR)$(sysconfdir)/abrt/plugins/Logger.conf # CCpp -libCCpp_la_SOURCES = CCpp.cpp CCpp.h +libCCpp_la_SOURCES = CCpp.cpp CCpp.h CCpp_sha1.cpp CCpp_sha1.h libCCpp_la_LDFLAGS = -avoid-version -libCCpp_la_LIBADD = $(NSS_LIBS) +#libCCpp_la_LIBADD = libCCpp_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils \ -DCCPP_HOOK_PATH=\"${libexecdir}/abrt-hook-ccpp\" \ -DDEBUG_DUMPS_DIR=\"$(DEBUG_DUMPS_DIR)\" \ - -DLOCALSTATEDIR='"$(localstatedir)"' \ - $(NSS_CFLAGS) + -DLOCALSTATEDIR='"$(localstatedir)"' # Firefox - disabled for now @@ -133,7 +133,7 @@ libTicketUploader_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils $(CUR libPython_la_SOURCES = Python.h Python.cpp #libPython_la_LIBADD = $(NSS_LIBS) libPython_la_LDFLAGS = -avoid-version -libPython_la_CPPFLAGS = $(NSS_CFLAGS) -I$(srcdir)/../../inc -I$(srcdir)/../Utils +libPython_la_CPPFLAGS = -I$(srcdir)/../../inc -I$(srcdir)/../Utils # FileTrasfer libFileTransfer_la_SOURCES = FileTransfer.cpp FileTransfer.h diff --git a/lib/Plugins/Python.conf b/lib/Plugins/Python.conf new file mode 100644 index 0000000..75d2229 --- /dev/null +++ b/lib/Plugins/Python.conf @@ -0,0 +1 @@ +Enabled = yes
\ No newline at end of file diff --git a/lib/Plugins/RunApp.cpp b/lib/Plugins/RunApp.cpp index f7cbc01..e2147e2 100644 --- a/lib/Plugins/RunApp.cpp +++ b/lib/Plugins/RunApp.cpp @@ -33,50 +33,38 @@ using namespace std; void CActionRunApp::Run(const char *pActionDir, const char *pArgs) { - /* Don't update_client() - actions run at crash time */ + /* Don't update_client() - actions run at crash time, there is no client + * to talk to at that point */ log("RunApp('%s','%s')", pActionDir, pArgs); vector_string_t args; parse_args(pArgs, args, '"'); + if (args.size() <= COMMAND) + { + return; + } const char *cmd = args[COMMAND].c_str(); if (!cmd[0]) { return; } -//FIXME: need to be able to escape " in .conf - /* Chdir to the dump dir. Command can analyze component and such. + /* NB: we chdir to the dump dir. Command can analyze component and such. * Example: * test x"`cat component`" = x"xorg-x11-apps" && cp /var/log/Xorg.0.log . */ -//Can do it using chdir() in child if we'd open-code popen - string cd_and_cmd = ssprintf("cd '%s'; %s", pActionDir, cmd); - VERB1 log("RunApp: executing '%s'", cd_and_cmd.c_str()); - FILE *fp = popen(cd_and_cmd.c_str(), "r"); - if (fp == NULL) - { - /* Happens only on resource starvation (fork fails or out-of-mem) */ - return; - } - -//FIXME: RunApp("gzip -9 </var/log/Xorg.0.log", "Xorg.0.log.gz") fails -//since we mangle NULs. - string output; - char line[1024]; - while (fgets(line, 1024, fp) != NULL) - { - if (args.size() > FILENAME) - output += line; - } - pclose(fp); + size_t cmd_out_size; + char *cmd_out = run_in_shell_and_save_output(/*flags:*/ 0, cmd, pActionDir, &cmd_out_size); if (args.size() > FILENAME) { CDebugDump dd; dd.Open(pActionDir); - dd.SaveText(args[FILENAME].c_str(), output.c_str()); + dd.SaveBinary(args[FILENAME].c_str(), cmd_out, cmd_out_size); } + + free(cmd_out); } PLUGIN_INFO(ACTION, diff --git a/lib/Plugins/SOSreport.cpp b/lib/Plugins/SOSreport.cpp index 6f23165..2576910 100644 --- a/lib/Plugins/SOSreport.cpp +++ b/lib/Plugins/SOSreport.cpp @@ -91,7 +91,9 @@ void CActionSOSreport::Run(const char *pActionDir, const char *pArgs) update_client(_("running sosreport: %s"), command.c_str()); std::string output = command; output += '\n'; - output += popen_and_save_output(command.c_str()); + char *command_out = run_in_shell_and_save_output(/*flags:*/ 0, command.c_str(), /*dir:*/ NULL, /*size_p:*/ NULL); + output += command_out; + free(command_out); update_client(_("done running sosreport")); std::string sosreport_filename = ParseFilename(output); @@ -101,8 +103,9 @@ void CActionSOSreport::Run(const char *pActionDir, const char *pArgs) dd.Open(pActionDir); //Not useful //dd.SaveText("sosreportoutput", output); - if (copy_file(sosreport_filename.c_str(), sosreport_dd_filename.c_str()) < 0) + if (copy_file(sosreport_filename.c_str(), sosreport_dd_filename.c_str(), 0644) < 0) { + dd.Close(); throw CABRTException(EXCEP_PLUGIN, "Can't copy '%s' to '%s'", sosreport_filename.c_str(), diff --git a/lib/Plugins/SQLite3.conf b/lib/Plugins/SQLite3.conf index 3773c8f..2053642 100644 --- a/lib/Plugins/SQLite3.conf +++ b/lib/Plugins/SQLite3.conf @@ -1,3 +1,4 @@ # Configuration file for database plugin SQLite3 + # DB path DBPath = /var/cache/abrt/abrt-db diff --git a/lib/Plugins/SQLite3.cpp b/lib/Plugins/SQLite3.cpp index 1979f24..ffcf05f 100644 --- a/lib/Plugins/SQLite3.cpp +++ b/lib/Plugins/SQLite3.cpp @@ -90,6 +90,26 @@ static const char *const upate_sql_commands[][ABRT_TABLE_VERSION + 1] = { }, }; + +/* Is this string safe wrt SQL injection? + * PHP's mysql_real_escape_string() treats \, ', ", \x00, \n, \r, and \x1a as special. + * We are a bit more paranoid and disallow any control chars. + */ +static bool is_string_safe(const char *str) +{ + const char *p = str; + while (*p) + { + if ((unsigned char)(*p) < ' ' || strchr("\\\"\'", *p)) + { + error_msg("Probable SQL injection: '%s'", str); + return false; + } + p++; + } + return true; +} + static void get_table(vector_database_rows_t& pTable, sqlite3 *db, const char *fmt, ...) { @@ -308,6 +328,14 @@ void CSQLite3::Insert_or_Update(const char *pUUID, const char *pDebugDumpPath, const char *pTime) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + || !is_string_safe(pDebugDumpPath) + || !is_string_safe(pTime) + ) { + return; + } + if (!exists_uuid_uid(m_pDB, pUUID, pUID)) { execute_sql(m_pDB, @@ -336,20 +364,26 @@ void CSQLite3::Insert_or_Update(const char *pUUID, void CSQLite3::DeleteRow(const char *pUUID, const char *pUID) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + ) { + return; + } + if (pUID[0] == '0' && !pUID[1]) { execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " "WHERE "COL_UUID" = '%s';", - pUUID, pUID + pUUID ); } else if (exists_uuid_uid(m_pDB, pUUID, pUID)) { execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " - "WHERE "COL_UUID" = '%s' " - "AND ("COL_UID" = '%s' OR "COL_UID" = '-1');", - pUUID, pUID + "WHERE "COL_UUID" = '%s' " + "AND ("COL_UID" = '%s' OR "COL_UID" = '-1');", + pUUID, pUID ); } else @@ -360,6 +394,11 @@ void CSQLite3::DeleteRow(const char *pUUID, const char *pUID) void CSQLite3::DeleteRows_by_dir(const char *dump_dir) { + if (!is_string_safe(dump_dir)) + { + return; + } + execute_sql(m_pDB, "DELETE FROM "ABRT_TABLE" " "WHERE "COL_DEBUG_DUMP_PATH" = '%s'", @@ -369,6 +408,13 @@ void CSQLite3::DeleteRows_by_dir(const char *dump_dir) void CSQLite3::SetReported(const char *pUUID, const char *pUID, const char *pMessage) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + || !is_string_safe(pMessage) + ) { + return; + } + if (pUID[0] == '0' && !pUID[1]) { execute_sql(m_pDB, @@ -409,6 +455,12 @@ void CSQLite3::SetReported(const char *pUUID, const char *pUID, const char *pMes vector_database_rows_t CSQLite3::GetUIDData(const char *pUID) { vector_database_rows_t table; + + if (!is_string_safe(pUID)) + { + return table; + } + if (pUID[0] == '0' && !pUID[1]) { get_table(table, m_pDB, "SELECT * FROM "ABRT_TABLE";"); @@ -426,6 +478,12 @@ vector_database_rows_t CSQLite3::GetUIDData(const char *pUID) database_row_t CSQLite3::GetRow(const char *pUUID, const char *pUID) { + if (!is_string_safe(pUUID) + || !is_string_safe(pUID) + ) { + return database_row_t(); + } + vector_database_rows_t table; if (pUID[0] == '0' && !pUID[1]) diff --git a/lib/Plugins/TicketUploader.cpp b/lib/Plugins/TicketUploader.cpp index a4fe0e8..608ee40 100644 --- a/lib/Plugins/TicketUploader.cpp +++ b/lib/Plugins/TicketUploader.cpp @@ -120,17 +120,14 @@ void CTicketUploader::SendFile(const char *pURL, const char *pFilename) throw CABRTException(EXCEP_PLUGIN, "Can't open archive file '%s'", pFilename); } struct stat buf; - if (fstat(fileno(f), &buf) == -1) /* TODO: never fails */ - { - throw CABRTException(EXCEP_PLUGIN, "Can't stat archive file '%s'", pFilename); - } + fstat(fileno(f), &buf); /* never fails */ CURL* curl = xcurl_easy_init(); /* enable uploading */ curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* specify target */ curl_easy_setopt(curl, CURLOPT_URL, wholeURL.c_str()); curl_easy_setopt(curl, CURLOPT_READDATA, f); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, buf.st_size); + curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)buf.st_size); /* everything is done here; result 0 means success */ result = curl_easy_perform(curl); /* goodbye */ @@ -221,7 +218,7 @@ string CTicketUploader::Report(const map_crash_report_t& pCrashReport, else if (it->second[CD_TYPE] == CD_BIN) { string ofile_name = concat_path_file(tmptar_name.c_str(), it->first.c_str()); - if (copy_file(it->second[CD_CONTENT].c_str(), ofile_name.c_str()) < 0) + if (copy_file(it->second[CD_CONTENT].c_str(), ofile_name.c_str(), 0644) < 0) { throw CABRTException(EXCEP_PLUGIN, "Can't copy '%s' to '%s'", @@ -399,19 +396,18 @@ void CTicketUploader::SetSettings(const map_plugin_settings_t& pSettings) } } -//ok to delete? -//const map_plugin_settings_t& CTicketUploader::GetSettings() -//{ -// m_pSettings["Customer"] = m_sCustomer; -// m_pSettings["Ticket"] = m_sTicket; -// m_pSettings["URL"] = m_sURL; -// m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no"; -// m_pSettings["Upload"] = m_bEncrypt ? "yes" : "no"; -// m_pSettings["RetryCount"] = to_string(m_nRetryCount); -// m_pSettings["RetryDelay"] = to_string(m_nRetryDelay); -// -// return m_pSettings; -//} +const map_plugin_settings_t& CTicketUploader::GetSettings() +{ + m_pSettings["Customer"] = m_sCustomer; + m_pSettings["Ticket"] = m_sTicket; + m_pSettings["URL"] = m_sURL; + m_pSettings["Encrypt"] = m_bEncrypt ? "yes" : "no"; + m_pSettings["Upload"] = m_bEncrypt ? "yes" : "no"; + m_pSettings["RetryCount"] = to_string(m_nRetryCount); + m_pSettings["RetryDelay"] = to_string(m_nRetryDelay); + + return m_pSettings; +} PLUGIN_INFO(REPORTER, CTicketUploader, diff --git a/lib/Plugins/TicketUploader.h b/lib/Plugins/TicketUploader.h index e00596f..1bc8f6b 100644 --- a/lib/Plugins/TicketUploader.h +++ b/lib/Plugins/TicketUploader.h @@ -27,7 +27,7 @@ #include "Plugin.h" #include "Reporter.h" -#include "CrashTypes.h" +//#include "CrashTypes.h" class CTicketUploader : public CReporter { @@ -45,8 +45,7 @@ class CTicketUploader : public CReporter public: CTicketUploader(); virtual ~CTicketUploader(); -//ok to delete? -// virtual const map_plugin_settings_t& GetSettings(); + virtual const map_plugin_settings_t& GetSettings(); virtual void SetSettings(const map_plugin_settings_t& pSettings); virtual std::string Report(const map_crash_report_t& pCrashReport, diff --git a/lib/Utils/CommLayerInner.cpp b/lib/Utils/CommLayerInner.cpp index 133e97d..4a3b80a 100644 --- a/lib/Utils/CommLayerInner.cpp +++ b/lib/Utils/CommLayerInner.cpp @@ -68,11 +68,9 @@ void update_client(const char *fmt, ...) va_list p; va_start(p, fmt); - char *msg; - int used = vasprintf(&msg, fmt, p); + char *msg = xvasprintf(fmt, p); va_end(p); - if (used < 0) - return; s_pObs->Status(msg, peer, key); + free(msg); } diff --git a/lib/Utils/DebugDump.cpp b/lib/Utils/DebugDump.cpp index b4c3ee4..a0a52ab 100644 --- a/lib/Utils/DebugDump.cpp +++ b/lib/Utils/DebugDump.cpp @@ -65,7 +65,9 @@ CDebugDump::CDebugDump() : m_sDebugDumpDir(""), m_pGetNextFileDir(NULL), m_bOpened(false), - m_bLocked(false) + m_bLocked(false), + m_uid(0), + m_gid(0) {} CDebugDump::~CDebugDump() @@ -97,6 +99,15 @@ void CDebugDump::Open(const char *pDir) } Lock(); m_bOpened = true; + /* In case caller would want to create more files, he'll need uid:gid */ + m_uid = 0; + m_gid = 0; + struct stat stat_buf; + if (stat(m_sDebugDumpDir.c_str(), &stat_buf) == 0) + { + m_uid = stat_buf.st_uid; + m_gid = stat_buf.st_gid; + } } bool CDebugDump::Exist(const char* pPath) @@ -115,7 +126,15 @@ static bool GetAndSetLock(const char* pLockFile, const char* pPID) char pid_buf[sizeof(pid_t)*3 + 4]; ssize_t r = readlink(pLockFile, pid_buf, sizeof(pid_buf) - 1); if (r < 0) + { + if (errno == ENOENT) + { + /* Looks like pLockFile was deleted */ + usleep(10 * 1000); /* avoid CPU eating loop */ + continue; + } perror_msg_and_die("Can't read lock file '%s'", pLockFile); + } pid_buf[r] = '\0'; if (strcmp(pid_buf, pPID) == 0) @@ -209,8 +228,8 @@ void CDebugDump::Lock() error_msg_and_die("Locking bug on '%s'", m_sDebugDumpDir.c_str()); std::string lockFile = m_sDebugDumpDir + ".lock"; - char pid_buf[sizeof(int)*3 + 2]; - sprintf(pid_buf, "%u", (unsigned)getpid()); + char pid_buf[sizeof(long)*3 + 2]; + sprintf(pid_buf, "%lu", (long)getpid()); while ((m_bLocked = GetAndSetLock(lockFile.c_str(), pid_buf)) != true) { sleep(1); /* was 0.5 seconds */ @@ -228,7 +247,26 @@ void CDebugDump::UnLock() } } -void CDebugDump::Create(const char *pDir, int64_t uid) +/* Create a fresh empty debug dump dir. + * + * Security: we should not allow users to write new files or write + * into existing ones, but they should be able to read them. + * + * @param uid + * Crashed application's User Id + * + * We currently have only three callers: + * kernel oops hook: uid=0 + * this hook runs under 0:0 + * ccpp hook: uid=uid of crashed user's binary + * this hook runs under 0:0 + * python hook: uid=uid of crashed user's script + * this hook runs under abrt:gid + * + * Currently, we set dir's gid to passwd(uid)->pw_gid parameter, and we set uid to + * abrt's user id. We do not allow write access to group. + */ +void CDebugDump::Create(const char *pDir, uid_t uid) { if (m_bOpened) { @@ -244,25 +282,45 @@ void CDebugDump::Create(const char *pDir, int64_t uid) Lock(); m_bOpened = true; - if (mkdir(m_sDebugDumpDir.c_str(), 0700) == -1) + /* Was creating it with mode 0700 and user as the owner, but this allows + * the user to replace any file in the directory, changing security-sensitive data + * (e.g. "uid", "analyzer", "executable") + */ + if (mkdir(m_sDebugDumpDir.c_str(), 0750) == -1) { UnLock(); m_bOpened = false; throw CABRTException(EXCEP_DD_OPEN, "Can't create dir '%s'", pDir); } - if (chmod(m_sDebugDumpDir.c_str(), 0700) == -1) + + /* mkdir's mode (above) can be affected by umask, fix it */ + if (chmod(m_sDebugDumpDir.c_str(), 0750) == -1) { UnLock(); m_bOpened = false; throw CABRTException(EXCEP_DD_OPEN, "Can't change mode of '%s'", pDir); } - struct passwd* pw = getpwuid(uid); - gid_t gid = pw ? pw->pw_gid : uid; - if (chown(m_sDebugDumpDir.c_str(), uid, gid) == -1) + + /* Get ABRT's user id */ + m_uid = 0; + struct passwd *pw = getpwnam("abrt"); + if (pw) + m_uid = pw->pw_uid; + else + error_msg("User 'abrt' does not exist, using uid 0"); + + /* Get crashed application's group id */ + m_gid = 0; + pw = getpwuid(uid); + if (pw) + m_gid = pw->pw_gid; + else + error_msg("User %lu does not exist, using gid 0", (long)uid); + + if (chown(m_sDebugDumpDir.c_str(), m_uid, m_gid) == -1) { - /* if /var/cache/abrt is writable by all, _aborting_ here is not useful */ - /* let's just warn */ - perror_msg("can't change '%s' ownership to %u:%u", m_sDebugDumpDir.c_str(), (int)uid, (int)gid); + perror_msg("can't change '%s' ownership to %lu:%lu", m_sDebugDumpDir.c_str(), + (long)m_uid, (long)m_gid); } SaveText(FILENAME_UID, to_string(uid).c_str()); @@ -294,7 +352,7 @@ static void DeleteFileDir(const char *pDir) } } closedir(dir); - if (remove(pDir) == -1) + if (rmdir(pDir) == -1) { throw CABRTException(EXCEP_DD_DELETE, "Can't remove dir %s", pDir); } @@ -359,12 +417,18 @@ static void LoadTextFile(const char *pPath, std::string& pData) fclose(fp); } -static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize) +static void SaveBinaryFile(const char *pPath, const char* pData, unsigned pSize, uid_t uid, gid_t gid) { - int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0666); + /* "Why 0640?!" See ::Create() for security analysis */ + unlink(pPath); + int fd = open(pPath, O_WRONLY | O_TRUNC | O_CREAT, 0640); if (fd < 0) { - throw CABRTException(EXCEP_DD_SAVE, "Can't open file '%s'", pPath); + throw CABRTException(EXCEP_DD_SAVE, "Can't open file '%s': %s", pPath, errno ? strerror(errno) : "errno == 0"); + } + if (fchown(fd, uid, gid) == -1) + { + perror_msg("can't change '%s' ownership to %lu:%lu", pPath, (long)uid, (long)gid); } unsigned r = full_write(fd, pData, pSize); close(fd); @@ -391,8 +455,9 @@ void CDebugDump::SaveText(const char* pName, const char* pData) throw CABRTException(EXCEP_DD_OPEN, "DebugDump is not opened"); } std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); - SaveBinaryFile(fullPath.c_str(), pData, strlen(pData)); + SaveBinaryFile(fullPath.c_str(), pData, strlen(pData), m_uid, m_gid); } + void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize) { if (!m_bOpened) @@ -400,7 +465,7 @@ void CDebugDump::SaveBinary(const char* pName, const char* pData, unsigned pSize throw CABRTException(EXCEP_DD_OPEN, "DebugDump is not opened"); } std::string fullPath = concat_path_file(m_sDebugDumpDir.c_str(), pName); - SaveBinaryFile(fullPath.c_str(), pData, pSize); + SaveBinaryFile(fullPath.c_str(), pData, pSize, m_uid, m_gid); } void CDebugDump::InitGetNextFile() diff --git a/lib/Utils/DebugDump.h b/lib/Utils/DebugDump.h index c59552e..d3eebb4 100644 --- a/lib/Utils/DebugDump.h +++ b/lib/Utils/DebugDump.h @@ -51,6 +51,8 @@ class CDebugDump DIR* m_pGetNextFileDir; bool m_bOpened; bool m_bLocked; + uid_t m_uid; + gid_t m_gid; void SaveKernelArchitectureRelease(); @@ -62,7 +64,7 @@ class CDebugDump ~CDebugDump(); void Open(const char *pDir); - void Create(const char *pDir, int64_t uid); + void Create(const char *pDir, uid_t uid); void Delete(); void Close(); diff --git a/lib/Utils/Makefile.am b/lib/Utils/Makefile.am index d5e9d98..a944d97 100644 --- a/lib/Utils/Makefile.am +++ b/lib/Utils/Makefile.am @@ -16,7 +16,7 @@ libABRTUtils_la_SOURCES = \ daemon.cpp \ skip_whitespace.cpp \ xatonum.cpp \ - popen_and_save_output.cpp \ + spawn.cpp \ stringops.cpp \ dirsize.cpp \ DebugDump.h DebugDump.cpp \ diff --git a/lib/Utils/Polkit.cpp b/lib/Utils/Polkit.cpp index c868e1a..a7e4a5d 100644 --- a/lib/Utils/Polkit.cpp +++ b/lib/Utils/Polkit.cpp @@ -46,14 +46,12 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) GCancellable * cancellable; authority = polkit_authority_get(); - cancellable = g_cancellable_new(); - g_timeout_add(POLKIT_TIMEOUT * 1000, + guint cancel_timeout = g_timeout_add(POLKIT_TIMEOUT * 1000, (GSourceFunc) do_cancel, cancellable); - result = polkit_authority_check_authorization_sync(authority, subject, action_id, @@ -61,7 +59,8 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION, cancellable, &error); - + g_object_unref(authority); + g_source_remove(cancel_timeout); if (error) { g_error_free(error); @@ -71,11 +70,18 @@ static PolkitResult do_check(PolkitSubject *subject, const char *action_id) if (result) { if (polkit_authorization_result_get_is_challenge(result)) + { /* Can't happen (happens only with * POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE flag) */ + g_object_unref(result); return PolkitChallenge; + } if (polkit_authorization_result_get_is_authorized(result)) + { + g_object_unref(result); return PolkitYes; + } + g_object_unref(result); return PolkitNo; } diff --git a/lib/Utils/abrt_dbus.h b/lib/Utils/abrt_dbus.h index bc9889a..25e099e 100644 --- a/lib/Utils/abrt_dbus.h +++ b/lib/Utils/abrt_dbus.h @@ -154,6 +154,9 @@ enum { ABRT_DBUS_ERROR = -1, ABRT_DBUS_LAST_FIELD = 0, ABRT_DBUS_MORE_FIELDS = 1, + /* note that dbus_message_iter_next() returns FALSE on last field + * and TRUE if there are more fields. + * It maps exactly on the above constants. */ }; /* Checks type, loads data, advances to the next arg. * Returns TRUE if next arg exists. diff --git a/lib/Utils/abrt_xmlrpc.cpp b/lib/Utils/abrt_xmlrpc.cpp index ae1d098..e3a4648 100644 --- a/lib/Utils/abrt_xmlrpc.cpp +++ b/lib/Utils/abrt_xmlrpc.cpp @@ -15,6 +15,16 @@ CURL* xcurl_easy_init() return curl; } +#if 1 +void throw_xml_fault(xmlrpc_env *env) +{ + std::string errmsg = ssprintf("XML-RPC Fault: %s(%d)", env->fault_string, env->fault_code); + xmlrpc_env_clean(env); // this is needed ONLY if fault_occurred + xmlrpc_env_init(env); // just in case user catches ex and _continues_ to use env + error_msg("%s", errmsg.c_str()); // show error in daemon log + throw CABRTException(EXCEP_PLUGIN, errmsg.c_str()); +} +#else void throw_if_xml_fault_occurred(xmlrpc_env *env) { if (env->fault_occurred) @@ -26,6 +36,7 @@ void throw_if_xml_fault_occurred(xmlrpc_env *env) throw CABRTException(EXCEP_PLUGIN, errmsg.c_str()); } } +#endif void abrt_xmlrpc_conn::new_xmlrpc_client(const char* url, bool no_ssl_verify) { @@ -60,15 +71,16 @@ void abrt_xmlrpc_conn::new_xmlrpc_client(const char* url, bool no_ssl_verify) PACKAGE_NAME, VERSION, &clientParms, XMLRPC_CPSIZE(transportparm_size), &m_pClient); - throw_if_xml_fault_occurred(&env); + if (env.fault_occurred) + throw_xml_fault(&env); m_pServer_info = xmlrpc_server_info_new(&env, url); if (env.fault_occurred) { xmlrpc_client_destroy(m_pClient); m_pClient = NULL; + throw_xml_fault(&env); } - throw_if_xml_fault_occurred(&env); } void abrt_xmlrpc_conn::destroy_xmlrpc_client() diff --git a/lib/Utils/abrt_xmlrpc.h b/lib/Utils/abrt_xmlrpc.h index 352e80c..a8bd2cc 100644 --- a/lib/Utils/abrt_xmlrpc.h +++ b/lib/Utils/abrt_xmlrpc.h @@ -24,7 +24,7 @@ struct abrt_xmlrpc_conn { }; /* Utility functions */ -void throw_if_xml_fault_occurred(xmlrpc_env *env); +void throw_xml_fault(xmlrpc_env *env); CURL* xcurl_easy_init(); #endif diff --git a/lib/Utils/copyfd.cpp b/lib/Utils/copyfd.cpp index 9abe752..fdc568a 100644 --- a/lib/Utils/copyfd.cpp +++ b/lib/Utils/copyfd.cpp @@ -106,7 +106,7 @@ off_t copyfd_eof(int fd1, int fd2) return full_fd_action(fd1, fd2, 0); } -off_t copy_file(const char *src_name, const char *dst_name) +off_t copy_file(const char *src_name, const char *dst_name, int mode) { off_t r; int src = open(src_name, O_RDONLY); @@ -115,7 +115,7 @@ off_t copy_file(const char *src_name, const char *dst_name) perror_msg("Can't open '%s'", src_name); return -1; } - int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, 0666); + int dst = open(dst_name, O_WRONLY | O_TRUNC | O_CREAT, mode); if (dst < 0) { close(src); diff --git a/lib/Utils/daemon.cpp b/lib/Utils/daemon.cpp index 7aa891c..0527062 100644 --- a/lib/Utils/daemon.cpp +++ b/lib/Utils/daemon.cpp @@ -78,12 +78,12 @@ static char *append_escaped(char *start, const char *s) #define COMMAND_LINE_SIZE 2048 char* get_cmdline(pid_t pid) { - char path[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; + char path[sizeof("/proc/%lu/cmdline") + sizeof(long)*3]; char cmdline[COMMAND_LINE_SIZE]; char escaped_cmdline[COMMAND_LINE_SIZE*4 + 4]; escaped_cmdline[1] = '\0'; - sprintf(path, "/proc/%u/cmdline", (int)pid); + sprintf(path, "/proc/%lu/cmdline", (long)pid); int fd = open(path, O_RDONLY); if (fd >= 0) { diff --git a/lib/Utils/popen_and_save_output.cpp b/lib/Utils/popen_and_save_output.cpp deleted file mode 100644 index 4bcbcac..0000000 --- a/lib/Utils/popen_and_save_output.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Utility routines. - * - * Licensed under GPLv2 or later, see file COPYING in this tarball for details. - */ -#include "abrtlib.h" - -using namespace std; - -string popen_and_save_output(const char *cmd) -{ - string result; - - FILE *fp = popen(cmd, "r"); - if (fp == NULL) /* fork or pipe failed; or out-of-mem */ - { - return result; - } - - size_t sz; - char buf[BUFSIZ + 1]; - while ((sz = fread(buf, 1, sizeof(buf)-1, fp)) > 0) - { - buf[sz] = '\0'; - result += buf; - } - pclose(fp); - - return result; -} diff --git a/lib/Utils/spawn.cpp b/lib/Utils/spawn.cpp new file mode 100644 index 0000000..d3e6ac6 --- /dev/null +++ b/lib/Utils/spawn.cpp @@ -0,0 +1,136 @@ +/* + * Utility routines. + * + * Licensed under GPLv2, see file COPYING in this tarball for details. + */ +#include "abrtlib.h" + +using namespace std; + +static string concat_str_vector(char **strings) +{ + string result; + while (*strings) { + result += *strings++; + if (*strings) + result += ' '; + } + return result; +} + +/* Returns pid */ +pid_t fork_execv_on_steroids(int flags, + char **argv, + int *pipefds, + char **unsetenv_vec, + const char *dir, + uid_t uid) +{ + pid_t child; + /* Reminder: [0] is read end, [1] is write end */ + int pipe_to_child[2]; + int pipe_fm_child[2]; + + /* Sanitize flags */ + if (!pipefds) + flags &= ~(EXECFLG_INPUT | EXECFLG_OUTPUT); + + if (flags & EXECFLG_INPUT) + xpipe(pipe_to_child); + if (flags & EXECFLG_OUTPUT) + xpipe(pipe_fm_child); + + fflush(NULL); + child = fork(); + if (child == -1) { + perror_msg_and_die("fork"); + } + if (child == 0) { + /* Child */ + + /* Play with stdio descriptors */ + if (flags & EXECFLG_INPUT) { + xmove_fd(pipe_to_child[0], STDIN_FILENO); + } else if (flags & EXECFLG_INPUT_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO); + } + if (flags & EXECFLG_OUTPUT) { + xmove_fd(pipe_fm_child[1], STDOUT_FILENO); + } else if (flags & EXECFLG_OUTPUT_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDOUT_FILENO); + } + if (flags & EXECFLG_ERR2OUT) { + /* Want parent to see errors in the same stream */ + xdup2(STDOUT_FILENO, STDERR_FILENO); + } else if (flags & EXECFLG_ERR_NUL) { + xmove_fd(xopen("/dev/null", O_RDWR), STDERR_FILENO); + } + + if (flags & EXECFLG_SETGUID) { + struct passwd* pw = getpwuid(uid); + gid_t gid = pw ? pw->pw_gid : uid; + setgroups(1, &gid); + xsetregid(gid, gid); + xsetreuid(uid, uid); + } + if (flags & EXECFLG_SETSID) + setsid(); + + if (unsetenv_vec) { + while (*unsetenv_vec) + unsetenv(*unsetenv_vec++); + } + + if (dir) + xchdir(dir); + + VERB1 log("Executing: %s", concat_str_vector(argv).c_str()); + execvp(argv[0], argv); + if (!(flags & EXECFLG_QUIET)) + perror_msg("Can't execute '%s'", argv[0]); + exit(127); /* shell uses this exitcode in this case */ + } + + if (flags & EXECFLG_INPUT) { + close(pipe_to_child[0]); + pipefds[1] = pipe_to_child[1]; + } + if (flags & EXECFLG_OUTPUT) { + close(pipe_fm_child[1]); + pipefds[0] = pipe_fm_child[0]; + } + + return child; +} + +char *run_in_shell_and_save_output(int flags, + const char *cmd, + const char *dir, + size_t *size_p) +{ + flags |= EXECFLG_OUTPUT; + flags &= ~EXECFLG_INPUT; + + const char *argv[] = { "/bin/sh", "sh", "-c", cmd, NULL }; + int pipeout[2]; + pid_t child = fork_execv_on_steroids(flags, (char **)argv, pipeout, + /*unsetenv_vec:*/ NULL, dir, /*uid (unused):*/ 0); + + size_t pos = 0; + char *result = NULL; + while (1) { + result = (char*) xrealloc(result, pos + 4*1024 + 1); + size_t sz = safe_read(pipeout[0], result + pos, 4*1024); + if (sz <= 0) { + break; + } + pos += sz; + } + result[pos] = '\0'; + if (size_p) + *size_p = pos; + close(pipeout[0]); + waitpid(child, NULL, 0); + + return result; +} diff --git a/lib/Utils/xatonum.cpp b/lib/Utils/xatonum.cpp index b096ca8..8314629 100644 --- a/lib/Utils/xatonum.cpp +++ b/lib/Utils/xatonum.cpp @@ -9,7 +9,7 @@ unsigned xatou(const char *numstr) { - unsigned r; + unsigned long r; int old_errno; char *e; @@ -19,7 +19,7 @@ unsigned xatou(const char *numstr) old_errno = errno; errno = 0; r = strtoul(numstr, &e, 10); - if (errno || numstr == e || *e != '\0') + if (errno || numstr == e || *e != '\0' || r > UINT_MAX) goto inval; /* error / no digits / illegal trailing chars */ errno = old_errno; /* Ok. So restore errno. */ return r; diff --git a/lib/Utils/xfuncs.cpp b/lib/Utils/xfuncs.cpp index 8621b5f..f360d33 100644 --- a/lib/Utils/xfuncs.cpp +++ b/lib/Utils/xfuncs.cpp @@ -141,6 +141,12 @@ off_t xlseek(int fd, off_t offset, int whence) return off; } +void xchdir(const char *path) +{ + if (chdir(path)) + perror_msg_and_die("chdir(%s)", path); +} + char* xvasprintf(const char *format, va_list p) { int r; @@ -152,8 +158,8 @@ char* xvasprintf(const char *format, va_list p) #else // Bloat for systems that haven't got the GNU extension. va_list p2; - r = vsnprintf(NULL, 0, format, p); va_copy(p2, p); + r = vsnprintf(NULL, 0, format, p); string_ptr = xmalloc(r+1); r = vsnprintf(string_ptr, r+1, format, p2); va_end(p2); @@ -365,13 +371,13 @@ bool string_to_bool(const char *s) void xsetreuid(uid_t ruid, uid_t euid) { if (setreuid(ruid, euid) != 0) - perror_msg_and_die("can't set %cid %d", 'u', (int)ruid); + perror_msg_and_die("can't set %cid %lu", 'u', (long)ruid); } -void xsetregid(gid_t rgid, uid_t egid) +void xsetregid(gid_t rgid, gid_t egid) { if (setregid(rgid, egid) != 0) - perror_msg_and_die("can't set %cid %d", 'g', (int)rgid); + perror_msg_and_die("can't set %cid %lu", 'g', (long)rgid); } uid_t getuidbyname(const char* login) @@ -9,9 +9,9 @@ msgid "" msgstr "" "Project-Id-Version: abrt.master.es\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" -"POT-Creation-Date: 2009-12-15 10:52+0000\n" -"PO-Revision-Date: 2009-12-15 11:51-0300\n" -"Last-Translator: Héctor Daniel Cabrera <logan@fedoraproject.org>\n" +"POT-Creation-Date: 2010-01-15 11:23+0000\n" +"PO-Revision-Date: 2010-01-15 10:06-0300\n" +"Last-Translator: Claudio Rodrigo Pereyra Diaz <claudio@pereyradiaz.com.ar>\n" "Language-Team: Fedora Spanish <fedora-trans-es@redhat.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -28,26 +28,26 @@ msgstr "Otro cliente ya está siendo ejecutado, intentando despertarlo." msgid "Got unexpected data from daemon (is the database properly updated?)." msgstr "Se obtienen datos inesperados desde el demonio (¿está la Base de Datos correctamente actualizada?)" -#: ../src/Gui/ABRTPlugin.py:55 +#: ../src/Gui/ABRTPlugin.py:56 +msgid "Not loaded plugins" +msgstr "Complementos no cargados" + +#: ../src/Gui/ABRTPlugin.py:57 msgid "Analyzer plugins" msgstr "Complementos analizadores" -#: ../src/Gui/ABRTPlugin.py:56 +#: ../src/Gui/ABRTPlugin.py:58 msgid "Action plugins" msgstr "Complementos de acción" -#: ../src/Gui/ABRTPlugin.py:57 +#: ../src/Gui/ABRTPlugin.py:59 msgid "Reporter plugins" msgstr "Complementos de informes" -#: ../src/Gui/ABRTPlugin.py:58 +#: ../src/Gui/ABRTPlugin.py:60 msgid "Database plugins" msgstr "Complementos de Bases de Datos" -#: ../src/Gui/ABRTPlugin.py:97 -msgid "Plugin name is not set, can't load its settings" -msgstr "No se puso el nombre del complemento, no se puede cargar su configuración" - #: ../src/Gui/CCDBusBackend.py:74 #: ../src/Gui/CCDBusBackend.py:97 msgid "Can't connect to system dbus" @@ -134,31 +134,31 @@ msgstr "Ay_uda" # Revisar si hay que traducir. # Ver como referencia los botones gtk que no habia que traducirlos #. add pixbuff separatelly -#: ../src/Gui/CCMainWindow.py:71 +#: ../src/Gui/CCMainWindow.py:77 msgid "Icon" msgstr "Icono" -#: ../src/Gui/CCMainWindow.py:79 +#: ../src/Gui/CCMainWindow.py:85 msgid "Package" msgstr "Paquete" -#: ../src/Gui/CCMainWindow.py:80 +#: ../src/Gui/CCMainWindow.py:86 msgid "Application" msgstr "Aplicación" -#: ../src/Gui/CCMainWindow.py:81 +#: ../src/Gui/CCMainWindow.py:87 msgid "Date" msgstr "Fecha" -#: ../src/Gui/CCMainWindow.py:82 +#: ../src/Gui/CCMainWindow.py:88 msgid "Crash count" msgstr "Cantidad de caÃdas" -#: ../src/Gui/CCMainWindow.py:83 +#: ../src/Gui/CCMainWindow.py:89 msgid "User" msgstr "Usuario" -#: ../src/Gui/CCMainWindow.py:149 +#: ../src/Gui/CCMainWindow.py:157 #, python-format msgid "" "Can't show the settings dialog\n" @@ -167,7 +167,7 @@ msgstr "" "No se puede mostrar el diálogo de configuración\n" "%s" -#: ../src/Gui/CCMainWindow.py:160 +#: ../src/Gui/CCMainWindow.py:168 #, python-format msgid "" "Unable to finish current task!\n" @@ -177,7 +177,7 @@ msgstr "" "%s" #. there is something wrong with the daemon if we cant get the dumplist -#: ../src/Gui/CCMainWindow.py:184 +#: ../src/Gui/CCMainWindow.py:195 #, python-format msgid "" "Error while loading the dumplist.\n" @@ -186,15 +186,15 @@ msgstr "" "Error intentando cargar la lista de volcado.\n" "%s" -#: ../src/Gui/CCMainWindow.py:221 +#: ../src/Gui/CCMainWindow.py:232 msgid "<b>This crash has been reported:</b>\n" msgstr "<b> Esta caÃda ha sido reportada:</b>\n" -#: ../src/Gui/CCMainWindow.py:231 +#: ../src/Gui/CCMainWindow.py:242 msgid "<b>Not reported!</b>" msgstr "<b>¡No informado!</b>" -#: ../src/Gui/CCMainWindow.py:280 +#: ../src/Gui/CCMainWindow.py:291 msgid "" "Unable to get report!\n" "Debuginfo is missing?" @@ -202,7 +202,7 @@ msgstr "" "Incapaz de conseguir el informe!\n" "¿Falta la información de la depuración?" -#: ../src/Gui/CCMainWindow.py:299 +#: ../src/Gui/CCMainWindow.py:314 #, python-format msgid "" "Reporting failed!\n" @@ -211,8 +211,8 @@ msgstr "" "¡El informe falló!\n" "%s" -#: ../src/Gui/CCMainWindow.py:318 -#: ../src/Gui/CCMainWindow.py:345 +#: ../src/Gui/CCMainWindow.py:333 +#: ../src/Gui/CCMainWindow.py:360 #, python-format msgid "Error getting the report: %s" msgstr "Error al obtener el informe: %s" @@ -435,45 +435,45 @@ msgstr "Ha sido detectado una caÃda en el paquete %s." msgid "ABRT service is not running" msgstr "El servicio ABRT no se está ejecutando" -#: ../src/Applet/CCApplet.cpp:196 +#: ../src/Applet/CCApplet.cpp:200 msgid "Warning" msgstr "Aviso" -#: ../src/Daemon/Daemon.cpp:473 +#: ../src/Daemon/Daemon.cpp:474 msgid "Report size exceeded the quota. Please check system's MaxCrashReportsSize value in abrt.conf." msgstr "El tamaño del informe excede la cuota. Por favor, verifique el valor de MaxCrashReportsSize del sistema en abrt.conf." -#: ../lib/Plugins/Bugzilla.cpp:202 +#: ../lib/Plugins/Bugzilla.cpp:265 #, c-format msgid "Bug is already reported: %i" msgstr "El error ya ha sido informado: %i" -#: ../lib/Plugins/Bugzilla.cpp:264 +#: ../lib/Plugins/Bugzilla.cpp:341 #, c-format msgid "New bug id: %i" msgstr "Nuevo id del error: %i" -#: ../lib/Plugins/Bugzilla.cpp:359 +#: ../lib/Plugins/Bugzilla.cpp:442 msgid "Checking for duplicates..." msgstr "Chequeando si hay duplicados..." -#: ../lib/Plugins/Bugzilla.cpp:362 +#: ../lib/Plugins/Bugzilla.cpp:445 msgid "Logging into bugzilla..." msgstr "Ingresando a bugzilla..." -#: ../lib/Plugins/Bugzilla.cpp:366 +#: ../lib/Plugins/Bugzilla.cpp:449 msgid "Empty login and password. Please check Bugzilla.conf" msgstr "Usuario y contraseña vacios. Por favor compruebe el archivo Bugzilla.conf" -#: ../lib/Plugins/Bugzilla.cpp:372 +#: ../lib/Plugins/Bugzilla.cpp:455 msgid "Checking CC..." msgstr "Chequeando CC..." -#: ../lib/Plugins/Bugzilla.cpp:381 +#: ../lib/Plugins/Bugzilla.cpp:464 msgid "Creating new bug..." msgstr "Creando un nuevo informe..." -#: ../lib/Plugins/Bugzilla.cpp:385 +#: ../lib/Plugins/Bugzilla.cpp:468 msgid "Logging out..." msgstr "Saliendo..." @@ -481,23 +481,23 @@ msgstr "Saliendo..." msgid "Getting local universal unique identification" msgstr "Obteniendo la identificación única universal local" -#: ../lib/Plugins/CCpp.cpp:254 +#: ../lib/Plugins/CCpp.cpp:257 msgid "Generating backtrace" msgstr "Generando seguimiento..." -#: ../lib/Plugins/CCpp.cpp:372 +#: ../lib/Plugins/CCpp.cpp:376 msgid "Starting debuginfo installation" msgstr "Iniciando la instalación de la información de depuración" -#: ../lib/Plugins/CCpp.cpp:524 +#: ../lib/Plugins/CCpp.cpp:527 msgid "Getting local universal unique identification..." msgstr "Obteniendo la identificación única universal local..." -#: ../lib/Plugins/CCpp.cpp:543 +#: ../lib/Plugins/CCpp.cpp:546 msgid "Getting global universal unique identification..." msgstr "Obteniendo la identificación única universal global..." -#: ../lib/Plugins/CCpp.cpp:685 +#: ../lib/Plugins/CCpp.cpp:725 msgid "Skipping debuginfo installation" msgstr "Omita la instalación de la información de depuración" @@ -511,7 +511,7 @@ msgid "Writing report to '%s'" msgstr "Escribiendo reporte en '%s'" #: ../lib/Plugins/FileTransfer.cpp:63 -#: ../lib/Plugins/FileTransfer.cpp:385 +#: ../lib/Plugins/FileTransfer.cpp:372 msgid "FileTransfer: URL not specified" msgstr "Transferencia de archivo: URL no especificada" @@ -520,16 +520,16 @@ msgstr "Transferencia de archivo: URL no especificada" msgid "Sending archive %s to %s" msgstr "Enviando archivo %s a %s" -#: ../lib/Plugins/FileTransfer.cpp:310 +#: ../lib/Plugins/FileTransfer.cpp:296 msgid "File Transfer: Creating a report..." msgstr "Transferencia de archivo: Creando un informe..." -#: ../lib/Plugins/FileTransfer.cpp:335 +#: ../lib/Plugins/FileTransfer.cpp:322 #, c-format msgid "Can't create and send an archive: %s" msgstr "No se puede crear y enviar un archivo: %s" -#: ../lib/Plugins/FileTransfer.cpp:360 +#: ../lib/Plugins/FileTransfer.cpp:347 #, c-format msgid "Can't create and send an archive %s" msgstr "No se puede crear y enviar un archivo %s" @@ -538,7 +538,7 @@ msgstr "No se puede crear y enviar un archivo %s" msgid "Creating kernel oops crash reports..." msgstr "Creando un informe de cuelgue de kernel oops..." -#: ../lib/Plugins/Mailx.cpp:164 +#: ../lib/Plugins/Mailx.cpp:147 msgid "Sending an email..." msgstr "Enviando un correo..." @@ -551,10 +551,13 @@ msgstr "Ejecutando complemento SOSreport..." msgid "running sosreport: %s" msgstr "ejecutando sosreport: %s" -#: ../lib/Plugins/SOSreport.cpp:95 +#: ../lib/Plugins/SOSreport.cpp:97 msgid "done running sosreport" msgstr "Sosreport corriendo" +#~ msgid "Plugin name is not set, can't load its settings" +#~ msgstr "" +#~ "No se puso el nombre del complemento, no se puede cargar su configuración" #~ msgid "Searching for debug-info packages..." #~ msgstr "Buscando paquetes de información del depurador..." #~ msgid "Downloading and installing debug-info packages..." @@ -2,17 +2,18 @@ # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # -#: ../src/Gui/CCReporterDialog.py:196 +#: ../src/Gui/CCReporterDialog.py:208 # Sam Friedmann <sam.friedmann@redhat.com>, 2009. # ratal <aymeric.rateau@gmail.com>, 2009. +# Aymeric Rateau <aymeric.rateau@gmail.com>, 2010. msgid "" msgstr "" "Project-Id-Version: abrt.master.fr\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" -"POT-Creation-Date: 2009-11-23 08:40+0000\n" -"PO-Revision-Date: 2009-11-29 20:10+0900\n" -"Last-Translator: ratal <aymeric.rateau@gmail.com>\n" -"Language-Team: Français <fedora-trans-fr@redhat.com>\n" +"POT-Creation-Date: 2010-01-08 15:37+0000\n" +"PO-Revision-Date: 2010-01-14 21:10+0100\n" +"Last-Translator: Aymeric Rateau <aymeric.rateau@gmail.com>\n" +"Language-Team: French <fedora-trans-fr@redhat.com>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -46,7 +47,7 @@ msgid "Database plugins" msgstr "Extensions de base de données" #: ../src/Gui/ABRTPlugin.py:97 -msgid "Plugin name is not set, can't load it's settings" +msgid "Plugin name is not set, can't load its settings" msgstr "" "Le nom de l'extension n'est pas défini, chargement de sa configuration " "impossible" @@ -55,59 +56,55 @@ msgstr "" msgid "Can't connect to system dbus" msgstr "Connexion au système dbus impossible" -#: ../src/Gui/CCDBusBackend.py:100 ../src/Gui/CCDBusBackend.py:103 +#: ../src/Gui/CCDBusBackend.py:104 ../src/Gui/CCDBusBackend.py:107 msgid "Please check if abrt daemon is running" msgstr "Veuillez vérifier que le démon abrt est en cours d'exécution." -#: ../src/Gui/CCDBusBackend.py:155 +#: ../src/Gui/CCDBusBackend.py:159 msgid "" -"Daemon did't return valid report info\n" +"Daemon didn't return valid report info\n" "Debuginfo is missing?" msgstr "" "Le démon n'a pas retourné d'informations valides\n" "Debuginfo est manquant ?" -#: ../src/Gui/ccgui.glade.h:1 ../src/Gui/report.glade.h:1 -msgid " " -msgstr " " - -#: ../src/Gui/ccgui.glade.h:2 +#: ../src/Gui/ccgui.glade.h:1 msgid "(C) 2009 Red Hat, Inc." msgstr "(C) 2009 Red Hat, Inc." -#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/CCMainWindow.py:246 -msgid "<b>Not reported!</b>" -msgstr "<b>Non signalé !</b>" - -#: ../src/Gui/ccgui.glade.h:4 -msgid "<span color=\"white\">Description</span>" -msgstr "<span color=\"white\">Description</span>" - -#: ../src/Gui/ccgui.glade.h:5 +#: ../src/Gui/ccgui.glade.h:2 msgid "About ABRT" msgstr "À propos d'ABRT" -#: ../src/Gui/ccgui.glade.h:6 ../src/Gui/abrt.desktop.in.h:1 +#: ../src/Gui/ccgui.glade.h:3 ../src/Gui/abrt.desktop.in.h:1 msgid "Automatic Bug Reporting Tool" msgstr "Automatic Bug Reporting Tool" -#: ../src/Gui/ccgui.glade.h:7 +#: ../src/Gui/ccgui.glade.h:4 msgid "Delete" msgstr "Supprimer" -#: ../src/Gui/ccgui.glade.h:8 +#: ../src/Gui/ccgui.glade.h:5 +msgid "Details" +msgstr "Détails" + +#: ../src/Gui/ccgui.glade.h:6 +msgid "Not Reported" +msgstr "Non signalé" + +#: ../src/Gui/ccgui.glade.h:7 msgid "Please wait.." msgstr "Veuillez patienter..." -#: ../src/Gui/ccgui.glade.h:9 +#: ../src/Gui/ccgui.glade.h:8 msgid "Plugins" msgstr "Extensions" -#: ../src/Gui/ccgui.glade.h:10 ../src/Gui/report.glade.h:4 +#: ../src/Gui/ccgui.glade.h:9 ../src/Gui/report.glade.h:6 msgid "Report" msgstr "Rapport" -#: ../src/Gui/ccgui.glade.h:11 +#: ../src/Gui/ccgui.glade.h:10 msgid "" "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 " @@ -135,48 +132,44 @@ msgstr "" "Vous devriez avoir reçu une copie de la Licence Publique Générale GNU avec " "ce logiciel. Si ce n'est pas le cas, voir <http://www.gnu.org/licenses/>." -#: ../src/Gui/ccgui.glade.h:16 -msgid "Working..." -msgstr "Traitement en cours..." - -#: ../src/Gui/ccgui.glade.h:17 +#: ../src/Gui/ccgui.glade.h:15 msgid "_Edit" msgstr "_Édition" -#: ../src/Gui/ccgui.glade.h:18 +#: ../src/Gui/ccgui.glade.h:16 msgid "_File" msgstr "_Fichier" -#: ../src/Gui/ccgui.glade.h:19 +#: ../src/Gui/ccgui.glade.h:17 msgid "_Help" msgstr "_Aide" #. add pixbuff separatelly -#: ../src/Gui/CCMainWindow.py:80 +#: ../src/Gui/CCMainWindow.py:76 msgid "Icon" msgstr "Icône" -#: ../src/Gui/CCMainWindow.py:88 +#: ../src/Gui/CCMainWindow.py:84 msgid "Package" msgstr "Paquet" -#: ../src/Gui/CCMainWindow.py:89 +#: ../src/Gui/CCMainWindow.py:85 msgid "Application" msgstr "Application" -#: ../src/Gui/CCMainWindow.py:90 +#: ../src/Gui/CCMainWindow.py:86 msgid "Date" msgstr "Date" -#: ../src/Gui/CCMainWindow.py:91 +#: ../src/Gui/CCMainWindow.py:87 msgid "Crash count" msgstr "Décompte d'incidents" -#: ../src/Gui/CCMainWindow.py:93 +#: ../src/Gui/CCMainWindow.py:88 msgid "User" msgstr "Utilisateur" -#: ../src/Gui/CCMainWindow.py:160 +#: ../src/Gui/CCMainWindow.py:156 #, python-format msgid "" "Can't show the settings dialog\n" @@ -185,7 +178,7 @@ msgstr "" "Affichage de l'interface de configuration impossible\n" "%s" -#: ../src/Gui/CCMainWindow.py:181 +#: ../src/Gui/CCMainWindow.py:167 #, python-format msgid "" "Unable to finish current task!\n" @@ -194,23 +187,25 @@ msgstr "" "Impossible de terminer la tâche actuelle !\n" "%s" -#: ../src/Gui/CCMainWindow.py:198 +#. there is something wrong with the daemon if we cant get the dumplist +#: ../src/Gui/CCMainWindow.py:194 #, python-format msgid "" -"Error while loading the dumplist, please check if abrt daemon is running\n" -" %s" +"Error while loading the dumplist.\n" +"%s" msgstr "" -"Erreur lors du chargement de dumplist, veuillez vérifier que le démon abrt " -"est bien en cours d'exécution\n" +"Erreur lors du chargement de dumplist.\n" " %s" -#: ../src/Gui/CCMainWindow.py:238 -msgid "<b>This crash has been reported, you can find the report(s) at:</b>\n" -msgstr "" -"<b>Cet incident a été signalé, vous pourrez trouver ce(s) rapport(s) à  :</" -"b>\n" +#: ../src/Gui/CCMainWindow.py:231 +msgid "<b>This crash has been reported:</b>\n" +msgstr "<b>Cet incident a été signalé :</b>\n" + +#: ../src/Gui/CCMainWindow.py:241 +msgid "<b>Not reported!</b>" +msgstr "<b>Non signalé !</b>" -#: ../src/Gui/CCMainWindow.py:298 +#: ../src/Gui/CCMainWindow.py:290 msgid "" "Unable to get report!\n" "Debuginfo is missing?" @@ -218,7 +213,7 @@ msgstr "" "Impossible de trouver le rapport !\n" "Debuginfo est manquant ?" -#: ../src/Gui/CCMainWindow.py:318 +#: ../src/Gui/CCMainWindow.py:309 #, python-format msgid "" "Reporting failed!\n" @@ -227,43 +222,52 @@ msgstr "" "Échec de la création de rapports !\n" "%s" -#: ../src/Gui/CCMainWindow.py:337 ../src/Gui/CCMainWindow.py:364 +#: ../src/Gui/CCMainWindow.py:328 ../src/Gui/CCMainWindow.py:355 #, python-format msgid "Error getting the report: %s" msgstr "Erreur lors de l'obtention du rapport : %s" -#: ../src/Gui/CCReporterDialog.py:182 +#: ../src/Gui/CCReporterDialog.py:136 +#, python-format +msgid "" +"Can't save plugin settings:\n" +" %s" +msgstr "" +"Imposible d'enregistrer la configuration de l'extension :\n" +" %s" + +#: ../src/Gui/CCReporterDialog.py:194 msgid "Brief description how to reproduce this or what you did..." msgstr "" "Brève description de la procédure à suivre pour reproduire ceci, ou de ce " "que vous avez fait..." -#: ../src/Gui/CCReporterDialog.py:224 +#: ../src/Gui/CCReporterDialog.py:239 #, python-format msgid "" "Reporting disabled because the backtrace is unusable.\n" -"Please try to install debuginfo manually using command:<span color=\"blue\"> " -"debuginfo-install %s </span>\n" +"Please try to install debuginfo manually using command: <b>debuginfo-install " +"%s</b> \n" "then use Refresh button to regenerate the backtrace." msgstr "" "Envoi du rapport désactivé car le backtrace est inutilisable.\n" -"Veuillez installer debuginfo en utilisant la commande :<span color=\"blue\"> " -"debuginfo-install %s </span>\n" +"Veuillez installer debuginfo en utilisant la commande : <b> " +"debuginfo-install %s </b>\n" "puis utilisez le bouton de rafraichissement pour régénérer le backtrace." -#: ../src/Gui/CCReporterDialog.py:226 -msgid "The bactrace is unusable, you can't report this!" +#: ../src/Gui/CCReporterDialog.py:241 +msgid "The backtrace is unusable, you can't report this!" msgstr "Le backtrace est inutilisable, vous ne pouvez pas signaler ce bogue." -#: ../src/Gui/CCReporterDialog.py:232 +#: ../src/Gui/CCReporterDialog.py:246 msgid "" -"The bactrace is incomplete, please make sure you provide good steps to " +"The backtrace is incomplete, please make sure you provide good steps to " "reproduce." msgstr "" "Le backtrace est incomplet, veuillez vous assurer de fournir les étapes pour " "reproduire le bogue." -#: ../src/Gui/CCReporterDialog.py:280 +#: ../src/Gui/CCReporterDialog.py:296 #, python-format msgid "" "<b>WARNING</b>, you're about to send data which might contain sensitive " @@ -274,14 +278,14 @@ msgstr "" "des informations confidentielles.\n" "Voulez-vous vraiment envoyer <b>%s</b> ?\n" -#: ../src/Gui/dialogs.glade.h:1 +#: ../src/Gui/dialogs.glade.h:1 ../src/Gui/report.glade.h:5 +msgid "Log" +msgstr "Log" + +#: ../src/Gui/dialogs.glade.h:2 msgid "Report done" msgstr "Rapport créé" -#: ../src/Gui/dialogs.glade.h:2 ../src/Gui/settings.glade.h:27 -msgid "gtk-ok" -msgstr "gtk-ok" - #: ../src/Gui/PluginSettingsUI.py:18 msgid "Can't find PluginDialog widget in UI description!" msgstr "" @@ -302,15 +306,23 @@ msgstr "la boite combinée n'est pas implémentée" msgid "Nothing to hydrate!" msgstr "Aucune donnée à afficher !" +#: ../src/Gui/report.glade.h:1 +msgid " " +msgstr " " + #: ../src/Gui/report.glade.h:2 -msgid "Comment" -msgstr "Commenter" +msgid "<b>Comment</b>" +msgstr "<b>Commenter</b>" #: ../src/Gui/report.glade.h:3 -msgid "How to reproduce (in a few simple steps)" -msgstr "Comment reproduire (en quelques étapes simples)" +msgid "<b>Following items will be sent</b>" +msgstr "<b>Les points suivants seront envoyés</b>" + +#: ../src/Gui/report.glade.h:4 +msgid "<b>How to reproduce (in a few simple steps)</b>" +msgstr "<b>Comment reproduire (en quelques étapes simples)</b>" -#: ../src/Gui/report.glade.h:5 +#: ../src/Gui/report.glade.h:7 msgid "Send" msgstr "Envoyer" @@ -322,11 +334,11 @@ msgstr "<b>Sélectionnez l'extension</b>" msgid "<b>Select database backend</b>" msgstr "<b>Sélectionnez le moteur de base de données</b>" -#: ../src/Gui/SettingsDialog.py:165 +#: ../src/Gui/SettingsDialog.py:166 msgid "Remove this job" msgstr "Supprimer ce travail" -#: ../src/Gui/SettingsDialog.py:208 +#: ../src/Gui/SettingsDialog.py:210 msgid "Remove this action" msgstr "Supprimer cette action" @@ -339,104 +351,92 @@ msgid "<b>Associated action</b>" msgstr "<b>Action associée</b>" #: ../src/Gui/settings.glade.h:3 +msgid "<b>Plugin details</b>" +msgstr "<b>Détails de l'extension</b>" + +#: ../src/Gui/settings.glade.h:4 msgid "<b>Plugin</b>" msgstr "<b>Extension</b>" -#: ../src/Gui/settings.glade.h:4 +#: ../src/Gui/settings.glade.h:5 msgid "<b>Time (or period)</b>" msgstr "<b>Durée (ou période)</b>" -#: ../src/Gui/settings.glade.h:5 +#: ../src/Gui/settings.glade.h:6 msgid "Analyzers, Actions, Reporters" msgstr "Analyseurs, actions, rapporteurs" -#: ../src/Gui/settings.glade.h:6 +#: ../src/Gui/settings.glade.h:7 msgid "Author:" msgstr "Auteur :" -#: ../src/Gui/settings.glade.h:7 +#: ../src/Gui/settings.glade.h:8 msgid "Blacklisted packages: " msgstr "Paquets sur liste noire : " -#: ../src/Gui/settings.glade.h:8 +#: ../src/Gui/settings.glade.h:9 msgid "C_onfigure plugin" msgstr "C_onfiguration de l'extension" -#: ../src/Gui/settings.glade.h:9 +#: ../src/Gui/settings.glade.h:10 msgid "Check package GPG signature" msgstr "Vérification de la signature GPG du paquet" -#: ../src/Gui/settings.glade.h:10 +#: ../src/Gui/settings.glade.h:11 msgid "Common" msgstr "Commun" -#: ../src/Gui/settings.glade.h:11 +#: ../src/Gui/settings.glade.h:12 msgid "Cron" msgstr "Cron" -#: ../src/Gui/settings.glade.h:12 +#: ../src/Gui/settings.glade.h:13 msgid "Database backend: " msgstr "Moteur de base de données : " -#: ../src/Gui/settings.glade.h:13 -msgid "Edit blacklisted packages" -msgstr "Édition des paquets sur liste noire" - #: ../src/Gui/settings.glade.h:14 +msgid "Description:" +msgstr "Description :" + +#: ../src/Gui/settings.glade.h:15 msgid "GPG Keys" msgstr "Clés GPG" -#: ../src/Gui/settings.glade.h:15 +#: ../src/Gui/settings.glade.h:16 msgid "GPG keys: " msgstr "Clés GPG :" -#: ../src/Gui/settings.glade.h:16 +#: ../src/Gui/settings.glade.h:17 msgid "Global Settings" msgstr "Paramètres globaux" -#: ../src/Gui/settings.glade.h:17 +#: ../src/Gui/settings.glade.h:18 msgid "Max coredump storage size(MB):" msgstr "Taille de stockage coredump maximal (en Mo) :" -#: ../src/Gui/settings.glade.h:18 -msgid "Nothing selected" -msgstr "Aucune sélection" - #: ../src/Gui/settings.glade.h:19 -msgid "Plugin Details" -msgstr "Détails de l'extension" +msgid "Name:" +msgstr "Nom :" #: ../src/Gui/settings.glade.h:20 msgid "Settings" msgstr "Paramètres" #: ../src/Gui/settings.glade.h:21 -msgid "This function is not implemented yet!" -msgstr "Cette fonction n'est pas encore implémentée !" - -#: ../src/Gui/settings.glade.h:22 msgid "Version:" msgstr "Version :" -#: ../src/Gui/settings.glade.h:23 +#: ../src/Gui/settings.glade.h:22 msgid "Web Site:" msgstr "Site web :" -#: ../src/Gui/settings.glade.h:24 -msgid "gtk-add" -msgstr "gtk-add" - -#: ../src/Gui/settings.glade.h:25 +#: ../src/Gui/settings.glade.h:23 msgid "gtk-cancel" msgstr "gtk-cancel" -#: ../src/Gui/settings.glade.h:26 -msgid "gtk-close" -msgstr "gtk-close" - -#: ../src/Gui/settings.glade.h:28 -msgid "gtk-remove" -msgstr "gtk-remove" +#: ../src/Gui/settings.glade.h:24 +msgid "gtk-ok" +msgstr "gtk-ok" #: ../src/Gui/abrt.desktop.in.h:2 msgid "View and report application crashes" @@ -447,15 +447,15 @@ msgstr "Visualiser et signaler les plantages de l'application" msgid "A crash in package %s has been detected" msgstr "Un incident a été détecté dans le paquet %s" -#: ../src/Applet/Applet.cpp:253 +#: ../src/Applet/Applet.cpp:254 msgid "ABRT service is not running" msgstr "Le service ABRT n'est pas en cours d'exécution" -#: ../src/Applet/CCApplet.cpp:196 +#: ../src/Applet/CCApplet.cpp:204 msgid "Warning" msgstr "Avertissement" -#: ../src/Daemon/Daemon.cpp:520 +#: ../src/Daemon/Daemon.cpp:478 msgid "" "Report size exceeded the quota. Please check system's MaxCrashReportsSize " "value in abrt.conf." @@ -463,11 +463,13 @@ msgstr "" "La taille du rapport dépasse le quota. Veuillez vérifier la valeur " "MaxCrashReportsSize du système dans abrt.conf." -#: ../lib/Plugins/Bugzilla.cpp:202, c-format +#: ../lib/Plugins/Bugzilla.cpp:202 +#, c-format msgid "Bug is already reported: %i" msgstr "Le bogue est déjà signalé : %i" -#: ../lib/Plugins/Bugzilla.cpp:264, c-format +#: ../lib/Plugins/Bugzilla.cpp:264 +#, c-format msgid "New bug id: %i" msgstr "Nouvel ID de bogue : %i" @@ -499,31 +501,23 @@ msgstr "Déconnexion..." msgid "Getting local universal unique identification" msgstr "Obtention de l'UUID locale" -#: ../lib/Plugins/CCpp.cpp:257 -msgid "Getting backtrace..." -msgstr "Obtention du parcours arrière..." - -#: ../lib/Plugins/CCpp.cpp:566 ../lib/Plugins/CCpp.cpp:693 -msgid "Searching for debug-info packages..." -msgstr "Recherche de paquets debug-info..." +#: ../lib/Plugins/CCpp.cpp:258 +msgid "Generating backtrace" +msgstr "Génération du parcours arrière..." -#: ../lib/Plugins/CCpp.cpp:628 ../lib/Plugins/CCpp.cpp:727 -msgid "Downloading and installing debug-info packages..." -msgstr "Téléchargement et installation des paquets debug-info..." +#: ../lib/Plugins/CCpp.cpp:377 +msgid "Starting debuginfo installation" +msgstr "Démarrage de l'installation de debuginfo" -#: ../lib/Plugins/CCpp.cpp:832 +#: ../lib/Plugins/CCpp.cpp:527 msgid "Getting local universal unique identification..." msgstr "Obtention de l'UUID locale..." -#: ../lib/Plugins/CCpp.cpp:851 +#: ../lib/Plugins/CCpp.cpp:546 msgid "Getting global universal unique identification..." msgstr "Obtention de l'UUID globale..." -#: ../lib/Plugins/CCpp.cpp:896 -msgid "Starting report creation..." -msgstr "Lancement de la création de rapport..." - -#: ../lib/Plugins/CCpp.cpp:929 +#: ../lib/Plugins/CCpp.cpp:702 msgid "Skipping debuginfo installation" msgstr "Ignorer l'installation de debug-info" @@ -531,27 +525,31 @@ msgstr "Ignorer l'installation de debug-info" msgid "Creating and submitting a report..." msgstr "Création et envoi d'un rapport..." -#: ../lib/Plugins/Logger.cpp:65 -msgid "Creating a report..." -msgstr "Création d'un rapport..." +#: ../lib/Plugins/Logger.cpp:82 +#, c-format +msgid "Writing report to '%s'" +msgstr "Écriture du rapport à « %s »" -#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:384 +#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:381 msgid "FileTransfer: URL not specified" msgstr "Transfert de fichier : URL non spécifié" -#: ../lib/Plugins/FileTransfer.cpp:67, c-format +#: ../lib/Plugins/FileTransfer.cpp:67 +#, c-format msgid "Sending archive %s to %s" msgstr "Envoi de l'archive %s vers %s" -#: ../lib/Plugins/FileTransfer.cpp:309 +#: ../lib/Plugins/FileTransfer.cpp:306 msgid "File Transfer: Creating a report..." msgstr "Transfert de fichier : Création d'un rapport" -#: ../lib/Plugins/FileTransfer.cpp:334, c-format +#: ../lib/Plugins/FileTransfer.cpp:331 +#, c-format msgid "Can't create and send an archive: %s" msgstr "Impossible de créer et d'envoyer une archive : %s" -#: ../lib/Plugins/FileTransfer.cpp:359, c-format +#: ../lib/Plugins/FileTransfer.cpp:356 +#, c-format msgid "Can't create and send an archive %s" msgstr "Impossible de créer et d'envoyer une archive %s" @@ -567,7 +565,8 @@ msgstr "Envoi d'un email..." msgid "Executing SOSreport plugin..." msgstr "Exécution de l'extension SOSreport..." -#: ../lib/Plugins/SOSreport.cpp:91, c-format +#: ../lib/Plugins/SOSreport.cpp:91 +#, c-format msgid "running sosreport: %s" msgstr "exécution de sosreport : %s" @@ -575,6 +574,42 @@ msgstr "exécution de sosreport : %s" msgid "done running sosreport" msgstr "exécution de sosreport terminée" +#~ msgid "<span color=\"white\">Description</span>" +#~ msgstr "<span color=\"white\">Description</span>" + +#~ msgid "Working..." +#~ msgstr "Traitement en cours..." + +#~ msgid "Edit blacklisted packages" +#~ msgstr "Édition des paquets sur liste noire" + +#~ msgid "Nothing selected" +#~ msgstr "Aucune sélection" + +#~ msgid "This function is not implemented yet!" +#~ msgstr "Cette fonction n'est pas encore implémentée !" + +#~ msgid "gtk-add" +#~ msgstr "gtk-add" + +#~ msgid "gtk-close" +#~ msgstr "gtk-close" + +#~ msgid "gtk-remove" +#~ msgstr "gtk-remove" + +#~ msgid "Searching for debug-info packages..." +#~ msgstr "Recherche de paquets debug-info..." + +#~ msgid "Downloading and installing debug-info packages..." +#~ msgstr "Téléchargement et installation des paquets debug-info..." + +#~ msgid "Starting report creation..." +#~ msgstr "Lancement de la création de rapport..." + +#~ msgid "Creating a report..." +#~ msgstr "Création d'un rapport..." + #~ msgid "Can't get username for uid %s" #~ msgstr "Impossible d'obtenir le nom d'utilisateur pour l'uid %s" @@ -6,14 +6,14 @@ # # Geert Warrink <geert.warrink@onsnet.nu>, 2009. # Richard van der Luit <nippur@fedoraproject.org>, 2009. -# Geert Warrink <geert.warrink@onsnet.nu>, 2009. +# Geert Warrink <geert.warrink@onsnet.nu>, 2009, 2010. #: ../src/Gui/CCReporterDialog.py:208 msgid "" msgstr "" "Project-Id-Version: abrt.master\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" -"POT-Creation-Date: 2009-12-15 16:54+0000\n" -"PO-Revision-Date: 2009-12-15 18:05+0100\n" +"POT-Creation-Date: 2010-01-14 15:35+0000\n" +"PO-Revision-Date: 2010-01-14 17:50+0100\n" "Last-Translator: Geert Warrink <geert.warrink@onsnet.nu>\n" "Language-Team: nl <fedora-trans-list@redhat.com>\n" "MIME-Version: 1.0\n" @@ -31,23 +31,27 @@ msgid "Got unexpected data from daemon (is the database properly updated?)." msgstr "" "Kreeg niet verwachte data van daemon (is de database correct vernieuwd?)." -#: ../src/Gui/ABRTPlugin.py:55 +#: ../src/Gui/ABRTPlugin.py:56 +msgid "Not loaded plugins" +msgstr "Niet geladen plugins" + +#: ../src/Gui/ABRTPlugin.py:57 msgid "Analyzer plugins" msgstr "Analyse plugins" -#: ../src/Gui/ABRTPlugin.py:56 +#: ../src/Gui/ABRTPlugin.py:58 msgid "Action plugins" msgstr "Actie plugins" -#: ../src/Gui/ABRTPlugin.py:57 +#: ../src/Gui/ABRTPlugin.py:59 msgid "Reporter plugins" msgstr "Rapporteer plugins" -#: ../src/Gui/ABRTPlugin.py:58 +#: ../src/Gui/ABRTPlugin.py:60 msgid "Database plugins" msgstr "Databse plugins" -#: ../src/Gui/ABRTPlugin.py:97 +#: ../src/Gui/ABRTPlugin.py:99 msgid "Plugin name is not set, can't load its settings" msgstr "Plugin naam is niet ingesteld, kan zijn instellingen niet laden" @@ -144,31 +148,31 @@ msgid "_Help" msgstr "_Hulp" #. add pixbuff separatelly -#: ../src/Gui/CCMainWindow.py:71 +#: ../src/Gui/CCMainWindow.py:76 msgid "Icon" msgstr "Icoon" -#: ../src/Gui/CCMainWindow.py:79 +#: ../src/Gui/CCMainWindow.py:84 msgid "Package" msgstr "Pakket" -#: ../src/Gui/CCMainWindow.py:80 +#: ../src/Gui/CCMainWindow.py:85 msgid "Application" msgstr "Toepassing" -#: ../src/Gui/CCMainWindow.py:81 +#: ../src/Gui/CCMainWindow.py:86 msgid "Date" msgstr "Datum" -#: ../src/Gui/CCMainWindow.py:82 +#: ../src/Gui/CCMainWindow.py:87 msgid "Crash count" msgstr "Crash count" -#: ../src/Gui/CCMainWindow.py:83 +#: ../src/Gui/CCMainWindow.py:88 msgid "User" msgstr "Gebruiker" -#: ../src/Gui/CCMainWindow.py:149 +#: ../src/Gui/CCMainWindow.py:156 #, python-format msgid "" "Can't show the settings dialog\n" @@ -177,7 +181,7 @@ msgstr "" "Kan de instellingen dialoog niet tonen\n" "%s" -#: ../src/Gui/CCMainWindow.py:160 +#: ../src/Gui/CCMainWindow.py:167 #, python-format msgid "" "Unable to finish current task!\n" @@ -187,7 +191,7 @@ msgstr "" "%s" #. there is something wrong with the daemon if we cant get the dumplist -#: ../src/Gui/CCMainWindow.py:187 +#: ../src/Gui/CCMainWindow.py:194 #, python-format msgid "" "Error while loading the dumplist.\n" @@ -196,15 +200,15 @@ msgstr "" "Fout tijdens het laden van de dumplijst.\n" "%s" -#: ../src/Gui/CCMainWindow.py:224 +#: ../src/Gui/CCMainWindow.py:231 msgid "<b>This crash has been reported:</b>\n" msgstr "<b>Deze crash is gerapporteerd:</b>\n" -#: ../src/Gui/CCMainWindow.py:234 +#: ../src/Gui/CCMainWindow.py:241 msgid "<b>Not reported!</b>" msgstr "<b>Niet gerapporteerd!</b>" -#: ../src/Gui/CCMainWindow.py:283 +#: ../src/Gui/CCMainWindow.py:290 msgid "" "Unable to get report!\n" "Debuginfo is missing?" @@ -212,7 +216,7 @@ msgstr "" "Kan geen rapport krijgen!\n" "Mist debuginfo?" -#: ../src/Gui/CCMainWindow.py:302 +#: ../src/Gui/CCMainWindow.py:309 #, python-format msgid "" "Reporting failed!\n" @@ -221,7 +225,7 @@ msgstr "" "Rapporteren mislukte!\n" "%s" -#: ../src/Gui/CCMainWindow.py:321 ../src/Gui/CCMainWindow.py:348 +#: ../src/Gui/CCMainWindow.py:328 ../src/Gui/CCMainWindow.py:355 #, python-format msgid "Error getting the report: %s" msgstr "Fout tijdens het verkrijgen van het rapport: %s" @@ -446,11 +450,11 @@ msgstr "Een crash in pakket %s is ontdekt" msgid "ABRT service is not running" msgstr "ABRT service draait niet" -#: ../src/Applet/CCApplet.cpp:196 +#: ../src/Applet/CCApplet.cpp:200 msgid "Warning" msgstr "Waarschuwing" -#: ../src/Daemon/Daemon.cpp:473 +#: ../src/Daemon/Daemon.cpp:474 msgid "" "Report size exceeded the quota. Please check system's MaxCrashReportsSize " "value in abrt.conf." @@ -458,37 +462,37 @@ msgstr "" "Rapport grootte overschreed quota. Controleer a.u.b. MaxCrashReportsSize " "waarde van het systeem in abrt.conf." -#: ../lib/Plugins/Bugzilla.cpp:202 +#: ../lib/Plugins/Bugzilla.cpp:265 #, c-format msgid "Bug is already reported: %i" msgstr "Bug is al aangemeld: %i" -#: ../lib/Plugins/Bugzilla.cpp:264 +#: ../lib/Plugins/Bugzilla.cpp:341 #, c-format msgid "New bug id: %i" msgstr "Nieuwe bug id: %i" -#: ../lib/Plugins/Bugzilla.cpp:359 +#: ../lib/Plugins/Bugzilla.cpp:442 msgid "Checking for duplicates..." msgstr "Controleren voor dubbele..." -#: ../lib/Plugins/Bugzilla.cpp:362 +#: ../lib/Plugins/Bugzilla.cpp:445 msgid "Logging into bugzilla..." msgstr "Inloggen bij bugzilla..." -#: ../lib/Plugins/Bugzilla.cpp:366 +#: ../lib/Plugins/Bugzilla.cpp:449 msgid "Empty login and password. Please check Bugzilla.conf" msgstr "Leeg login en wachtwoord. Check a.u.b. Bugzilla.conf" -#: ../lib/Plugins/Bugzilla.cpp:372 +#: ../lib/Plugins/Bugzilla.cpp:455 msgid "Checking CC..." msgstr "Controleren van CC..." -#: ../lib/Plugins/Bugzilla.cpp:381 +#: ../lib/Plugins/Bugzilla.cpp:464 msgid "Creating new bug..." msgstr "Nieuwe bug aanmaken..." -#: ../lib/Plugins/Bugzilla.cpp:385 +#: ../lib/Plugins/Bugzilla.cpp:468 msgid "Logging out..." msgstr "Uitloggen..." @@ -496,23 +500,23 @@ msgstr "Uitloggen..." msgid "Getting local universal unique identification" msgstr "Verkrijgen van locale universele unieke identificatie" -#: ../lib/Plugins/CCpp.cpp:254 +#: ../lib/Plugins/CCpp.cpp:257 msgid "Generating backtrace" msgstr "Aangemaakte backtrace" -#: ../lib/Plugins/CCpp.cpp:372 +#: ../lib/Plugins/CCpp.cpp:376 msgid "Starting debuginfo installation" msgstr "Start debuginfo installatie" -#: ../lib/Plugins/CCpp.cpp:522 +#: ../lib/Plugins/CCpp.cpp:527 msgid "Getting local universal unique identification..." msgstr "Verkrijgen van locale universele unieke identificatie..." -#: ../lib/Plugins/CCpp.cpp:541 +#: ../lib/Plugins/CCpp.cpp:546 msgid "Getting global universal unique identification..." msgstr "Verkrijgen van golbale universele unieke identificatie..." -#: ../lib/Plugins/CCpp.cpp:683 +#: ../lib/Plugins/CCpp.cpp:725 msgid "Skipping debuginfo installation" msgstr "Sla debuginfo installatie over" @@ -525,7 +529,7 @@ msgstr "Aanmaken en indienen van rapport..." msgid "Writing report to '%s'" msgstr "Rapport schrijven naar: '%s'" -#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:385 +#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:372 msgid "FileTransfer: URL not specified" msgstr "Bestandsoverdracht: URL niet opgegeven" @@ -534,16 +538,16 @@ msgstr "Bestandsoverdracht: URL niet opgegeven" msgid "Sending archive %s to %s" msgstr "Versturen van archief %s naar %s" -#: ../lib/Plugins/FileTransfer.cpp:310 +#: ../lib/Plugins/FileTransfer.cpp:296 msgid "File Transfer: Creating a report..." msgstr "Bestandsoverdracht: Een rapport maken..." -#: ../lib/Plugins/FileTransfer.cpp:335 +#: ../lib/Plugins/FileTransfer.cpp:322 #, c-format msgid "Can't create and send an archive: %s" msgstr "Kan geen archief maken en versturen: %s" -#: ../lib/Plugins/FileTransfer.cpp:360 +#: ../lib/Plugins/FileTransfer.cpp:347 #, c-format msgid "Can't create and send an archive %s" msgstr "Kan archief %s niet aanmaken en versturen" @@ -552,7 +556,7 @@ msgstr "Kan archief %s niet aanmaken en versturen" msgid "Creating kernel oops crash reports..." msgstr "Aanmaken van kernel oops crash rapporten..." -#: ../lib/Plugins/Mailx.cpp:164 +#: ../lib/Plugins/Mailx.cpp:147 msgid "Sending an email..." msgstr "Versturen van email..." @@ -565,7 +569,7 @@ msgstr "Uitvoeren van SOSreport plugin..." msgid "running sosreport: %s" msgstr "sosreport draaien: %s" -#: ../lib/Plugins/SOSreport.cpp:95 +#: ../lib/Plugins/SOSreport.cpp:97 msgid "done running sosreport" msgstr "klaar met het draaien van sosreport" @@ -7,10 +7,10 @@ msgid "" msgstr "" "Project-Id-Version: pl\n" "Report-Msgid-Bugs-To: jmoskovc@redhat.com\n" -"POT-Creation-Date: 2009-12-19 09:12+0000\n" -"PO-Revision-Date: 2009-12-19 10:37+0100\n" +"POT-Creation-Date: 2010-01-14 20:43+0000\n" +"PO-Revision-Date: 2010-01-14 22:51+0100\n" "Last-Translator: Piotr DrÄ…g <piotrdrag@gmail.com>\n" -"Language-Team: Polish <fedora-trans-pl@redhat.com>\n" +"Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -25,26 +25,26 @@ msgstr "" "Otrzymano nieoczekiwane dane od demona (czy baza danych zostaÅ‚a wÅ‚aÅ›ciwie " "zaktualizowana?)." -#: ../src/Gui/ABRTPlugin.py:55 +#: ../src/Gui/ABRTPlugin.py:56 +msgid "Not loaded plugins" +msgstr "Nie wczytano wtyczek" + +#: ../src/Gui/ABRTPlugin.py:57 msgid "Analyzer plugins" msgstr "Wtyczki analizy" -#: ../src/Gui/ABRTPlugin.py:56 +#: ../src/Gui/ABRTPlugin.py:58 msgid "Action plugins" msgstr "Wtyczki dziaÅ‚aÅ„" -#: ../src/Gui/ABRTPlugin.py:57 +#: ../src/Gui/ABRTPlugin.py:59 msgid "Reporter plugins" msgstr "Wtyczki zgÅ‚aszania" -#: ../src/Gui/ABRTPlugin.py:58 +#: ../src/Gui/ABRTPlugin.py:60 msgid "Database plugins" msgstr "Wtyczki baz danych" -#: ../src/Gui/ABRTPlugin.py:97 -msgid "Plugin name is not set, can't load its settings" -msgstr "Nie ustawiono nazwy wtyczki, nie można wczytać jej ustawieÅ„" - #: ../src/Gui/CCDBusBackend.py:74 ../src/Gui/CCDBusBackend.py:97 msgid "Can't connect to system dbus" msgstr "Nie można połączyć siÄ™ z systemowÄ… magistralÄ… D-Bus" @@ -140,31 +140,31 @@ msgid "_Help" msgstr "Pomo_c" #. add pixbuff separatelly -#: ../src/Gui/CCMainWindow.py:71 +#: ../src/Gui/CCMainWindow.py:77 msgid "Icon" msgstr "Ikona" -#: ../src/Gui/CCMainWindow.py:79 +#: ../src/Gui/CCMainWindow.py:85 msgid "Package" msgstr "Pakiet" -#: ../src/Gui/CCMainWindow.py:80 +#: ../src/Gui/CCMainWindow.py:86 msgid "Application" msgstr "Aplikacja" -#: ../src/Gui/CCMainWindow.py:81 +#: ../src/Gui/CCMainWindow.py:87 msgid "Date" msgstr "Data" -#: ../src/Gui/CCMainWindow.py:82 +#: ../src/Gui/CCMainWindow.py:88 msgid "Crash count" msgstr "Liczba awarii" -#: ../src/Gui/CCMainWindow.py:83 +#: ../src/Gui/CCMainWindow.py:89 msgid "User" msgstr "Użytkownik" -#: ../src/Gui/CCMainWindow.py:149 +#: ../src/Gui/CCMainWindow.py:157 #, python-format msgid "" "Can't show the settings dialog\n" @@ -173,7 +173,7 @@ msgstr "" "Nie można wyÅ›wietlić okna dialogowego ustawieÅ„\n" "%s" -#: ../src/Gui/CCMainWindow.py:160 +#: ../src/Gui/CCMainWindow.py:168 #, python-format msgid "" "Unable to finish current task!\n" @@ -183,7 +183,7 @@ msgstr "" "%s" #. there is something wrong with the daemon if we cant get the dumplist -#: ../src/Gui/CCMainWindow.py:187 +#: ../src/Gui/CCMainWindow.py:195 #, python-format msgid "" "Error while loading the dumplist.\n" @@ -192,15 +192,15 @@ msgstr "" "Błąd podczas wczytywania listy zrzutów.\n" "%s" -#: ../src/Gui/CCMainWindow.py:224 +#: ../src/Gui/CCMainWindow.py:232 msgid "<b>This crash has been reported:</b>\n" msgstr "<b>Ta awaria zostaÅ‚a zgÅ‚oszona:</b>\n" -#: ../src/Gui/CCMainWindow.py:234 +#: ../src/Gui/CCMainWindow.py:242 msgid "<b>Not reported!</b>" msgstr "<b>Nie zgÅ‚oszono.</b>" -#: ../src/Gui/CCMainWindow.py:283 +#: ../src/Gui/CCMainWindow.py:291 msgid "" "Unable to get report!\n" "Debuginfo is missing?" @@ -208,7 +208,7 @@ msgstr "" "Nie można uzyskać raportu.\n" "Brak pakietów debuginfo?" -#: ../src/Gui/CCMainWindow.py:302 +#: ../src/Gui/CCMainWindow.py:310 #, python-format msgid "" "Reporting failed!\n" @@ -217,7 +217,7 @@ msgstr "" "ZgÅ‚oszenie nie powiodÅ‚o siÄ™.\n" "%s" -#: ../src/Gui/CCMainWindow.py:321 ../src/Gui/CCMainWindow.py:348 +#: ../src/Gui/CCMainWindow.py:329 ../src/Gui/CCMainWindow.py:356 #, python-format msgid "Error getting the report: %s" msgstr "Błąd podczas uzyskiwania raportu: %s" @@ -447,11 +447,11 @@ msgstr "Wykryto awariÄ™ pakietu %s" msgid "ABRT service is not running" msgstr "UsÅ‚uga ABRT nie jest uruchomiona" -#: ../src/Applet/CCApplet.cpp:196 +#: ../src/Applet/CCApplet.cpp:200 msgid "Warning" msgstr "Ostrzeżenie" -#: ../src/Daemon/Daemon.cpp:478 +#: ../src/Daemon/Daemon.cpp:474 msgid "" "Report size exceeded the quota. Please check system's MaxCrashReportsSize " "value in abrt.conf." @@ -459,37 +459,37 @@ msgstr "" "Wielkość raportu przekroczyÅ‚a dozwolone ograniczenie. ProszÄ™ sprawdzić " "wartość zmiennej MaxCrashReportsSize w pliku abrt.conf" -#: ../lib/Plugins/Bugzilla.cpp:202 +#: ../lib/Plugins/Bugzilla.cpp:265 #, c-format msgid "Bug is already reported: %i" msgstr "Błąd zostaÅ‚ już wczeÅ›niej zgÅ‚oszony: %i" -#: ../lib/Plugins/Bugzilla.cpp:264 +#: ../lib/Plugins/Bugzilla.cpp:341 #, c-format msgid "New bug id: %i" msgstr "Identyfikator nowego błędu: %i" -#: ../lib/Plugins/Bugzilla.cpp:359 +#: ../lib/Plugins/Bugzilla.cpp:442 msgid "Checking for duplicates..." msgstr "Sprawdzanie duplikatów..." -#: ../lib/Plugins/Bugzilla.cpp:362 +#: ../lib/Plugins/Bugzilla.cpp:445 msgid "Logging into bugzilla..." msgstr "Logowanie do Bugzilli..." -#: ../lib/Plugins/Bugzilla.cpp:366 +#: ../lib/Plugins/Bugzilla.cpp:449 msgid "Empty login and password. Please check Bugzilla.conf" msgstr "Pola login i hasÅ‚o sÄ… puste. ProszÄ™ sprawdzić plik Bugzilla.conf" -#: ../lib/Plugins/Bugzilla.cpp:372 +#: ../lib/Plugins/Bugzilla.cpp:455 msgid "Checking CC..." msgstr "Sprawdzanie listy CC..." -#: ../lib/Plugins/Bugzilla.cpp:381 +#: ../lib/Plugins/Bugzilla.cpp:464 msgid "Creating new bug..." msgstr "Dodawanie nowego błędu..." -#: ../lib/Plugins/Bugzilla.cpp:385 +#: ../lib/Plugins/Bugzilla.cpp:468 msgid "Logging out..." msgstr "Wylogowywanie..." @@ -501,19 +501,19 @@ msgstr "Uzyskiwanie lokalnego uniwersalnego, unikalnego identyfikatora" msgid "Generating backtrace" msgstr "Tworzenie wyjÄ…tku" -#: ../lib/Plugins/CCpp.cpp:375 +#: ../lib/Plugins/CCpp.cpp:376 msgid "Starting debuginfo installation" msgstr "Uruchamianie instalacji pakietów debuginfo" -#: ../lib/Plugins/CCpp.cpp:525 +#: ../lib/Plugins/CCpp.cpp:527 msgid "Getting local universal unique identification..." msgstr "Uzyskiwanie lokalnego uniwersalnego, unikalnego identyfikatora..." -#: ../lib/Plugins/CCpp.cpp:544 +#: ../lib/Plugins/CCpp.cpp:546 msgid "Getting global universal unique identification..." msgstr "Uzyskiwanie globalnego uniwersalnego, unikalnego identyfikatora..." -#: ../lib/Plugins/CCpp.cpp:687 +#: ../lib/Plugins/CCpp.cpp:725 msgid "Skipping debuginfo installation" msgstr "Pomijanie instalacji pakietu debuginfo" @@ -526,7 +526,7 @@ msgstr "Tworzenie i wysyÅ‚anie raportu..." msgid "Writing report to '%s'" msgstr "Zapisywanie raportu do \"%s\"" -#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:381 +#: ../lib/Plugins/FileTransfer.cpp:63 ../lib/Plugins/FileTransfer.cpp:372 msgid "FileTransfer: URL not specified" msgstr "Wtyczka przesyÅ‚ania plików: nie podano adresu URL" @@ -535,16 +535,16 @@ msgstr "Wtyczka przesyÅ‚ania plików: nie podano adresu URL" msgid "Sending archive %s to %s" msgstr "WysyÅ‚anie archiwum %s do %s" -#: ../lib/Plugins/FileTransfer.cpp:306 +#: ../lib/Plugins/FileTransfer.cpp:296 msgid "File Transfer: Creating a report..." msgstr "Wtyczka przesyÅ‚ania plików: tworzenie raportu..." -#: ../lib/Plugins/FileTransfer.cpp:331 +#: ../lib/Plugins/FileTransfer.cpp:322 #, c-format msgid "Can't create and send an archive: %s" msgstr "Nie można utworzyć i wysÅ‚ać archiwum: %s" -#: ../lib/Plugins/FileTransfer.cpp:356 +#: ../lib/Plugins/FileTransfer.cpp:347 #, c-format msgid "Can't create and send an archive %s" msgstr "Nie można utworzyć i wysÅ‚ać archiwum %s" @@ -553,7 +553,7 @@ msgstr "Nie można utworzyć i wysÅ‚ać archiwum %s" msgid "Creating kernel oops crash reports..." msgstr "Tworzenie raportów awarii \"kernel oops\"" -#: ../lib/Plugins/Mailx.cpp:164 +#: ../lib/Plugins/Mailx.cpp:147 msgid "Sending an email..." msgstr "WysÅ‚anie wiadomoÅ›ci e-mail..." @@ -566,6 +566,6 @@ msgstr "Wykonywanie wtyczki SOSreport..." msgid "running sosreport: %s" msgstr "wykonywanie sosreport: %s" -#: ../lib/Plugins/SOSreport.cpp:95 +#: ../lib/Plugins/SOSreport.cpp:97 msgid "done running sosreport" msgstr "ukoÅ„czono wykonywanie sosreport" 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); |
