diff options
author | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-20 18:24:12 +0200 |
---|---|---|
committer | Denys Vlasenko <dvlasenk@redhat.com> | 2010-10-20 18:24:12 +0200 |
commit | 451d3d730c7d1ff93031848882e43813ee3c346f (patch) | |
tree | 3d5363314986cdfdf470fd394f0157afbf6187a4 /lib/plugins/RHTSupport.cpp | |
parent | fefd0611427a2b4aa5c3337399c6120d0bca11d5 (diff) | |
download | abrt-451d3d730c7d1ff93031848882e43813ee3c346f.tar.gz abrt-451d3d730c7d1ff93031848882e43813ee3c346f.tar.xz abrt-451d3d730c7d1ff93031848882e43813ee3c346f.zip |
move rhtsupport reporting to a separate program (abrt-action-rhtsupport)
The tool works similarly to abrt-action-bugzilla:
Usage: abrt-action-rhtsupport -c CONFFILE -d DIR [-vs]
Report a crash to RHTSupport
Options:
-c FILE Configuration file (may be given many times)
-d DIR Crash dump directory
-v Verbose
-s Log to syslog
Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com>
Diffstat (limited to 'lib/plugins/RHTSupport.cpp')
-rw-r--r-- | lib/plugins/RHTSupport.cpp | 353 |
1 files changed, 84 insertions, 269 deletions
diff --git a/lib/plugins/RHTSupport.cpp b/lib/plugins/RHTSupport.cpp index 016d5a91..5c9109e7 100644 --- a/lib/plugins/RHTSupport.cpp +++ b/lib/plugins/RHTSupport.cpp @@ -17,11 +17,7 @@ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#define _GNU_SOURCE 1 /* for stpcpy */ -#include <libtar.h> #include "abrtlib.h" -#include "abrt_curl.h" -#include "abrt_rh_support.h" #include "crash_types.h" #include "abrt_exception.h" #include "comm_layer_inner.h" @@ -29,296 +25,115 @@ using namespace std; - -#if 0 //unused -static char *xml_escape(const char *str) -{ - const char *s = str; - unsigned count = 1; /* for NUL */ - while (*s) - { - if (*s == '&') - count += sizeof("&")-2; - if (*s == '<') - count += sizeof("<")-2; - if (*s == '>') - count += sizeof(">")-2; - if ((unsigned char)*s > 126 || (unsigned char)*s < ' ') - count += sizeof("\\x00")-2; - count++; - s++; - } - char *result = (char*)xmalloc(count); - char *d = result; - s = str; - while (*s) - { - if (*s == '&') - d = stpcpy(d, "&"); - else if (*s == '<') - d = stpcpy(d, "<"); - else if (*s == '>') - d = stpcpy(d, ">"); - else - if ((unsigned char)*s > 126 - || ( (unsigned char)*s < ' ' - && *s != '\t' - && *s != '\n' - && *s != '\r' - ) - ) { - *d++ = '\\'; - *d++ = 'x'; - *d++ = "0123456789abcdef"[(unsigned char)*s >> 4]; - *d++ = "0123456789abcdef"[(unsigned char)*s & 0xf]; - } - else - *d++ = *s; - s++; - } - *d = '\0'; - return result; -} -#endif - - -/* - * CReporterRHticket - */ - CReporterRHticket::CReporterRHticket() { - m_login = NULL; - m_password = NULL; - m_ssl_verify = true; - m_strata_url = xstrdup("https://api.access.redhat.com/rs"); + m_pSettings["URL"] = "https://api.access.redhat.com/rs"; + m_pSettings["Login"] = ""; + m_pSettings["Password"] = ""; + m_pSettings["SSLVerify"] = "yes"; } CReporterRHticket::~CReporterRHticket() { - free(m_login); - free(m_password); - free(m_strata_url); } -string CReporterRHticket::Report(const map_crash_data_t& pCrashData, - const map_plugin_settings_t& pSettings, - const char *pArgs) +void CReporterRHticket::SetSettings(const map_plugin_settings_t& pSettings) { - /* Gzipping e.g. 0.5gig coredump takes a while. Let client know what we are doing */ - update_client(_("Compressing data")); - - string retval; + /* Can't simply do this: - map_plugin_settings_t::const_iterator end = pSettings.end(); - map_plugin_settings_t::const_iterator it; - it = pSettings.find("URL"); - char *url = (it == end ? m_strata_url : xstrdup(it->second.c_str())); - - it = pSettings.find("Login"); - char *login = (it == end ? m_login : xstrdup(it->second.c_str())); - - it = pSettings.find("Password"); - char *password = (it == end ? m_password : xstrdup(it->second.c_str())); - - it = pSettings.find("SSLVerify"); - bool ssl_verify = (it == end ? m_ssl_verify : string_to_bool(it->second.c_str())); - - const char *package = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_PACKAGE); -// const string& component = get_crash_data_item_content(pCrashData, FILENAME_COMPONENT); -// const string& release = get_crash_data_item_content(pCrashData, FILENAME_RELEASE); -// const string& arch = get_crash_data_item_content(pCrashData, FILENAME_ARCHITECTURE); -// const string& duphash = get_crash_data_item_content(pCrashData, FILENAME_DUPHASH); - const char *reason = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_REASON); - const char *function = get_crash_data_item_content_or_NULL(pCrashData, FILENAME_CRASH_FUNCTION); - - struct strbuf *buf_summary = strbuf_new(); - strbuf_append_strf(buf_summary, "[abrt] %s", package); - - if (function && strlen(function) < 30) - strbuf_append_strf(buf_summary, ": %s", function); - - if (reason) - strbuf_append_strf(buf_summary, ": %s", reason); - - char *summary = strbuf_free_nobuf(buf_summary); - - char *bz_dsc = make_description_bz(pCrashData); - char *dsc = xasprintf("abrt version: "VERSION"\n%s", bz_dsc); - free(bz_dsc); - - reportfile_t* file = new_reportfile(); + m_pSettings = pSettings; - /* SELinux guys are not happy with /tmp, using /var/run/abrt */ - char *tempfile = xasprintf(LOCALSTATEDIR"/run/abrt/tmp-%lu-%lu.tar.gz", (long)getpid(), (long)time(NULL)); + * - it will erase keys which aren't present in pSettings. + * Example: if Bugzilla.conf doesn't have "Login = foo", + * then there's no pSettings["Login"] and m_pSettings = pSettings + * will nuke default m_pSettings["Login"] = "", + * making GUI think that we have no "Login" key at all + * and thus never overriding it - even if it *has* an override! + */ - int pipe_from_parent_to_child[2]; - xpipe(pipe_from_parent_to_child); - pid_t child = fork(); - if (child == 0) + map_plugin_settings_t::iterator it = m_pSettings.begin(); + while (it != m_pSettings.end()) { - /* child */ - close(pipe_from_parent_to_child[1]); - xmove_fd(xopen3(tempfile, O_WRONLY | O_CREAT | O_EXCL, 0600), 1); - xmove_fd(pipe_from_parent_to_child[0], 0); - execlp("gzip", "gzip", NULL); - perror_msg_and_die("can't execute '%s'", "gzip"); - } - close(pipe_from_parent_to_child[0]); - - TAR *tar = NULL; - if (tar_fdopen(&tar, pipe_from_parent_to_child[1], tempfile, - /*fileops:(standard)*/ NULL, O_WRONLY | O_CREAT, 0644, TAR_GNU) != 0) - { - retval = "can't create temporary file in "LOCALSTATEDIR"/run/abrt"; - goto ret; - } - - { - map_crash_data_t::const_iterator it = pCrashData.begin(); - for (; it != pCrashData.end(); it++) + map_plugin_settings_t::const_iterator override = pSettings.find(it->first); + if (override != pSettings.end()) { - if (it->first == CD_COUNT) continue; - if (it->first == CD_DUMPDIR) continue; - if (it->first == CD_INFORMALL) continue; - if (it->first == CD_REPORTED) continue; - if (it->first == CD_MESSAGE) continue; // plugin's status message (if we already reported it yesterday) - if (it->first == FILENAME_DESCRIPTION) continue; // package description - - const char *content = it->second[CD_CONTENT].c_str(); - if (it->second[CD_TYPE] == CD_TXT) - { - reportfile_add_binding_from_string(file, it->first.c_str(), content); - } - else if (it->second[CD_TYPE] == CD_BIN) - { - const char *basename = strrchr(content, '/'); - if (basename) - basename++; - else - basename = content; - char *xml_name = concat_path_file("content", basename); - reportfile_add_binding_from_namedfile(file, - /*on_disk_filename */ content, - /*binding_name */ it->first.c_str(), - /*recorded_filename*/ xml_name, - /*binary */ 1); - if (tar_append_file(tar, (char*)content, xml_name) != 0) - { - retval = "can't create temporary file in "LOCALSTATEDIR"/run/abrt"; - free(xml_name); - goto ret; - } - free(xml_name); - } - } - } - - /* Write out content.xml in the tarball's root */ - { - const char *signature = reportfile_as_string(file); - unsigned len = strlen(signature); - unsigned len512 = (len + 511) & ~511; - char *block = (char*)memcpy(xzalloc(len512), signature, len); - th_set_type(tar, S_IFREG | 0644); - th_set_mode(tar, S_IFREG | 0644); - //th_set_link(tar, char *linkname); - //th_set_device(tar, dev_t device); - //th_set_user(tar, uid_t uid); - //th_set_group(tar, gid_t gid); - //th_set_mtime(tar, time_t fmtime); - th_set_path(tar, (char*)"content.xml"); - th_set_size(tar, len); - th_finish(tar); /* caclulate and store th xsum etc */ - if (th_write(tar) != 0 - || full_write(tar_fd(tar), block, len512) != len512 - || tar_close(tar) != 0 - ) { - free(block); - retval = "can't create temporary file in "LOCALSTATEDIR"/run/abrt"; - goto ret; + VERB3 log(" rhtsupport settings[%s]='%s'", it->first.c_str(), it->second.c_str()); + it->second = override->second; } - tar = NULL; - free(block); - } - - { - update_client(_("Creating a new case...")); - char* result = send_report_to_new_case(url, - login, - password, - ssl_verify, - summary, - dsc, - package, - tempfile - ); - VERB3 log("post result:'%s'", result); - retval = result; - free(result); - } - - ret: - // Damn, selinux does not allow SIGKILLing our own child! wtf?? - //kill(child, SIGKILL); /* just in case */ - waitpid(child, NULL, 0); - if (tar) - tar_close(tar); - //close(pipe_from_parent_to_child[1]); - tar_close() does it itself - unlink(tempfile); - free(tempfile); - reportfile_free(file); - - free(summary); - free(dsc); - - if (strncasecmp(retval.c_str(), "error", 5) == 0) - { - throw CABRTException(EXCEP_PLUGIN, "%s", retval.c_str()); + it++; } - return retval; } -void CReporterRHticket::SetSettings(const map_plugin_settings_t& pSettings) +string CReporterRHticket::Report(const map_crash_data_t& crash_data, + const map_plugin_settings_t& settings, + const char *args) { - m_pSettings = pSettings; - - map_plugin_settings_t::const_iterator end = pSettings.end(); - map_plugin_settings_t::const_iterator it; - it = pSettings.find("URL"); - if (it != end) - { - free(m_strata_url); - m_strata_url = xstrdup(it->second.c_str()); - } - it = pSettings.find("Login"); - if (it != end) - { - free(m_login); - m_login = xstrdup(it->second.c_str()); - } - it = pSettings.find("Password"); - if (it != end) + /* abrt-action-bugzilla [-s] -c /etc/arbt/Bugzilla.conf -c - -d pCrashData.dir NULL */ + char *argv[9]; + char **pp = argv; + *pp++ = (char*)"abrt-action-rhtsupport"; + +//We want to consume output, so don't redirect to syslog. +// if (logmode & LOGMODE_SYSLOG) +// *pp++ = (char*)"-s"; +//TODO: the actions<->daemon interaction will be changed anyway... + + *pp++ = (char*)"-c"; + *pp++ = (char*)(PLUGINS_CONF_DIR"/RHTSupport."PLUGINS_CONF_EXTENSION); + *pp++ = (char*)"-c"; + *pp++ = (char*)"-"; + *pp++ = (char*)"-d"; + *pp++ = (char*)get_crash_data_item_content_or_NULL(crash_data, CD_DUMPDIR); + *pp = NULL; + int pipefds[2]; + pid_t pid = fork_execv_on_steroids(EXECFLG_INPUT + EXECFLG_OUTPUT + EXECFLG_ERR2OUT, + argv, + pipefds, + /* unsetenv_vec: */ NULL, + /* dir: */ NULL, + /* uid(unused): */ 0 + ); + + /* Write the configuration to stdin */ + map_plugin_settings_t::const_iterator it = settings.begin(); + while (it != settings.end()) { - free(m_password); - m_password = xstrdup(it->second.c_str()); + full_write_str(pipefds[1], it->first.c_str()); + full_write_str(pipefds[1], "="); + full_write_str(pipefds[1], it->second.c_str()); + full_write_str(pipefds[1], "\n"); + it++; } - it = pSettings.find("SSLVerify"); - if (it != end) + close(pipefds[1]); + + FILE *fp = fdopen(pipefds[0], "r"); + if (!fp) + die_out_of_memory(); + + /* Consume log from stdout */ + std::string bug_status; + char buf[512]; + while (fgets(buf, sizeof(buf), fp)) { - m_ssl_verify = string_to_bool(it->second.c_str()); + strchrnul(buf, '\n')[0] = '\0'; + if (strncmp(buf, "STATUS:", 7) == 0) + bug_status = buf + 7; + else + if (strncmp(buf, "EXCEPT:", 7) == 0) + { + fclose(fp); + waitpid(pid, NULL, 0); + throw CABRTException(EXCEP_PLUGIN, "%s", buf + 7); + } + else + update_client("%s", buf); } -} -/* Should not be deleted (why?) */ -const map_plugin_settings_t& CReporterRHticket::GetSettings() -{ - m_pSettings["URL"] = (m_strata_url)? m_strata_url: ""; - m_pSettings["Login"] = (m_login)? m_login: ""; - m_pSettings["Password"] = (m_password)? m_password: ""; - m_pSettings["SSLVerify"] = m_ssl_verify ? "yes" : "no"; + fclose(fp); /* this also closes pipefds[0] */ + /* wait for child to actually exit, and prevent leaving a zombie behind */ + waitpid(pid, NULL, 0); - return m_pSettings; + return bug_status; } PLUGIN_INFO(REPORTER, |