/*
Copyright (C) 2010 ABRT team
Copyright (C) 2010 RedHat Inc
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <libtar.h>
#include "ureport.h"
#include "internal_libreport.h"
#include "client.h"
#include "libreport_curl.h"
#include "abrt_rh_support.h"
#include "reporter-rhtsupport.h"
#include "problem_report.h"
/* problem report format template */
#define PROBLEM_REPORT_TEMPLATE \
"%summary:: [abrt] [[%pkg_name%]][[: %crash_function%()]][[: %reason%]][[: TAINTED %tainted_short%]]\n" \
"\n" \
"Description of problem:: %bare_comment\n" \
"\n" \
"Additional info::" \
" count,reason,package,pkg_vendor,cmdline,executable,%reporter\n" \
"\n" \
"How reproducible:: %bare_reproducible\n" \
"\n" \
"Steps to reproduce:: %bare_reproducer\n" \
"\n" \
"Truncated backtrace:: %bare_%short_backtrace\n" \
"\n" \
"Other report identifiers:: %bare_reported_to\n"
#define ABRT_ELEMENTS_KB_ARTICLE "https://access.redhat.com/articles/2134281"
#define RHTSUPPORT_CASE_URL_PATH "cases"
#define QUERY_HINTS_IF_SMALLER_THAN (8*1024*1024)
static void ask_rh_credentials(char **login, char **password);
#define INVALID_CREDENTIALS_LOOP(l, p, r, fncall) \
do {\
r = fncall;\
if (r->error == 0 || r->http_resp_code != 401 ) { break; }\
ask_rh_credentials(&l, &p);\
free_rhts_result(r);\
} while (1)
#define STRCPY_IF_NOT_EQUAL(dest, src) \
do { if (strcmp(dest, src) != 0 ) { \
free(dest); \
dest = xstrdup(src); \
} } while (0)
static report_result_t *get_reported_to(const char *dump_dir_name)
{
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
xfunc_die();
report_result_t *reported_to = find_in_reported_to(dd, "RHTSupport");
dd_close(dd);
return reported_to;
}
static
int create_tarball(const char *tempfile, struct dump_dir *dd,
problem_data_t *problem_data)
{
reportfile_t *file = NULL;
int retval = 0; /* everything is ok so far .. */
int pipe_from_parent_to_child[2];
xpipe(pipe_from_parent_to_child);
pid_t child = fork();
if (child == 0)
{
/* 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], (char*)tempfile,
/*fileops:(standard)*/ NULL, O_WRONLY | O_CREAT, 0644, TAR_GNU) != 0)
{
goto ret_fail;
}
file = new_reportfile();
{
GHashTableIter iter;
char *name;
struct problem_item *value;
g_hash_table_iter_init(&iter, problem_data);
while (g_hash_table_iter_next(&iter, (void**)&name, (void**)&value))
{
const char *content = value->content;
if (value->flags & CD_FLAG_TXT)
{
reportfile_add_binding_from_string(file, name, content);
}
else if (value->flags & CD_FLAG_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 */ name,
/*recorded_filename*/ xml_name,
/*binary */ !(value->flags & CD_FLAG_BIGTXT)
);
free(xml_name);
}
}
}
/* append all files from dump dir */
dd_init_next_file(dd);
char *short_name, *full_name;
while (dd_get_next_file(dd, &short_name, &full_name))
{
char *uploaded_name = concat_path_file("content", short_name);
free(short_name);
if (tar_append_file(tar, full_name, uploaded_name) != 0)
{
free(full_name);
goto ret_fail;
}
free(full_name);
}
const char *signature = reportfile_as_string(file);
/*
* Note: this pointer points to string which is owned by
* "file" object, can't free "file" just yet.
*/
/* Write out content.xml in the tarball's root */
{
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(NULL));
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 /* writes header block */
/* writes content.xml, padded to 512 bytes */
|| full_write(tar_fd(tar), block, len512) != len512
|| tar_append_eof(tar) != 0 /* writes EOF blocks */
|| tar_close(tar) != 0
) {
free(block);
goto ret_fail;
}
tar = NULL;
free(block);
}
/* We must be sure gzip finished, and finished successfully */
int status;
safe_waitpid(child, &status, 0);
child = -1;
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
{
/* Hopefully, by this time child emitted more meaningful
* error message. But just in case it didn't:
*/
goto ret_fail;
}
goto ret_clean; /* success */
ret_fail:
retval = 1; /* failure */
/* We must close write fd first, or else child will wait forever */
if (tar)
tar_close(tar);
//close(pipe_from_parent_to_child[1]); - tar_close() does it itself
/* Now wait for child to exit */
if (child > 0)
{
// Damn, selinux does not allow SIGKILLing our own child! wtf??
//kill(child, SIGKILL); /* just in case */
safe_waitpid(child, NULL, 0);
}
ret_clean:
dd_close(dd);
/* now it's safe to free file */
free_reportfile(file);
return retval;
}
static
bool check_for_hints(const char *url, char **login, char **password, bool ssl_verify, const char *tempfile)
{
bool retval = false;
rhts_result_t *result = NULL;
INVALID_CREDENTIALS_LOOP((*login), (*password),
result, get_rhts_hints(url, *login, *password, ssl_verify, tempfile)
);
#if 0 /* testing */
log_warning("ERR:%d", result->error);
log_warning("MSG:'%s'", result->msg);
log_warning("BODY:'%s'", result->body);
result->error = 0;
result->body = xstrdup(
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
"<problems xmlns=\"http://www.redhat.com/gss/strata\">"
"<link uri=\"http://access.redhat.com/\" rel=\"help\">The main Red Hat Support web site</link>"
"<property name=\"content\">an ABRT report</property>"
"<problem>"
"<property name=\"source\">a backtrace in the ABRT report</property>"
"<link uri=\"https://avalon-ci.gss.redhat.com/kb/docs/DOC-22029\" rel=\"suggestion\">[RHEL 5.3] EVO autocompletion lookup hang</link>"
"</problem>"
"</problems>"
);
#endif
if (result->error)
{
/* We don't use result->msg here because it looks like this:
* Error in file upload at 'URL', HTTP code: 404,
* server says: '<?xml...?><error...><code>404</code><message>...</message></error>'
* TODO: make server send bare textual msgs, not XML.
*/
error_msg("Error in file upload at '%s', HTTP code: %d", url, result->http_resp_code);
}
else if (result->body)
{
/* The message might contain URLs to known solutions and such */
char *hint = parse_response_from_RHTS_hint_xml2txt(result->body);
if (hint)
{
hint = append_to_malloced_string(hint, " ");
hint = append_to_malloced_string(hint,
_("Do you still want to create a RHTSupport ticket?")
);
/*
* 'Yes' to the create ticket question means no hints were found.
*/
retval = !ask_yes_no(hint);
free(hint);
}
}
free_rhts_result(result);
return retval;
}
static
char *ask_rh_login(const char *message)
{
char *login = ask(message);
if (login == NULL || login[0] == '\0')
{
set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
error_msg_and_die(_("Can't continue without login"));
}
return login;
}
static
char *ask_rh_password(const char *message)
{
char *password = ask_password(message);
if (password == NULL || password[0] == '\0')
{
set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
error_msg_and_die(_("Can't continue without password"));
}
return password;
}
static
void ask_rh_credentials(char **login, char **password)
{
free(*login);
free(*password);
*login = ask_rh_login(_("Invalid password or login. Please enter your Red Hat login:"));
char *question = xasprintf(_("Invalid password or login. Please enter the password for '%s':"), *login);
*password = ask_rh_password(question);
free(question);
}
static
char *get_param_string(const char *name, map_string_t *settings, const char *dflt)
{
char *envname = xasprintf("RHTSupport_%s", name);
const char *envvar = getenv(envname);
free(envname);
return xstrdup(envvar ? envvar : (get_map_string_item_or_NULL(settings, name) ? : dflt));
}
static char *create_case_url(char *url, const char *case_no)
{
char *url1 = concat_path_file(url, RHTSUPPORT_CASE_URL_PATH);
free(url);
url = concat_path_file(url1, case_no);
free(url1);
return url;
}
static char *ask_case_no_create_url(char *url)
{
char *msg = xasprintf(_("Please enter customer case number to which you want to attach the data:"));
char *case_no = ask(msg);
free(msg);
if (case_no == NULL || case_no[0] == '\0')
{
set_xfunc_error_retval(EXIT_CANCEL_BY_USER);
error_msg_and_die(_("Can't continue without Red Hat Support case number"));
}
char *new_url = create_case_url(url, (const char *)case_no);
free(case_no);
return new_url;
}
int main(int argc, char **argv)
{
abrt_init(argv);
/* I18n */
setlocale(LC_ALL, "");
#if ENABLE_NLS
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
#endif
const char *dump_dir_name = ".";
const char *case_no = NULL;
GList *conf_file = NULL;
const char *fmt_file = NULL;
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
"\n"
"& [-v] [-c CONFFILE] [-F FMTFILE] -d DIR\n"
"or:\n"
"& [-v] [-c CONFFILE] [-d DIR] -t[ID] [-u -C UR_CONFFILE] FILE...\n"
"\n"
"Reports a problem to RHTSupport.\n"
"\n"
"If not specified, CONFFILE defaults to "CONF_DIR"/plugins/rhtsupport.conf\n"
"and user's local ~"USER_HOME_CONFIG_PATH"/rhtsupport.conf.\n"
"Its lines should have 'PARAM = VALUE' format.\n"
"Recognized string parameters: URL, Login, Password, BigFileURL.\n"
"Recognized numeric parameter: BigSizeMB.\n"
"Recognized boolean parameter (VALUE should be 1/0, yes/no): SSLVerify.\n"
"User's local configuration overrides the system wide configuration.\n"
"Parameters can be overridden via $RHTSupport_PARAM environment variables.\n"
"\n"
"Option -t uploads FILEs to the already created case on RHTSupport site.\n"
"The case ID is retrieved from directory specified by -d DIR.\n"
"If problem data in DIR was never reported to Red Hat Support, you will be asked\n"
"to enter case ID to which you want to upload the FILEs.\n"
"\n"
"Option -tCASE uploads FILEs to the case CASE on RHTSupport site.\n"
"-d DIR is ignored.\n"
);
enum {
OPT_v = 1 << 0,
OPT_d = 1 << 1,
OPT_c = 1 << 2,
OPT_t = 1 << 3,
OPT_f = 1 << 4,
OPT_F = 1 << 5,
OPT_D = 1 << 6,
};
/* Keep enum above and order of options below in sync! */
struct options program_options[] = {
OPT__VERBOSE(&g_verbose),
OPT_STRING( 'd', NULL, &dump_dir_name, "DIR" , _("Problem directory")),
OPT_LIST( 'c', NULL, &conf_file , "FILE", _("Configuration file (may be given many times)")),
OPT_OPTSTRING('t', NULL, &case_no , "ID" , _("Upload FILEs [to case with this ID]")),
OPT_BOOL( 'f', NULL, NULL , _("Force reporting even if this problem is already reported")),
OPT_STRING( 'F', NULL, &fmt_file , "FILE", _("Formatting file for a new case")),
OPT_BOOL( 'D', NULL, NULL , _("Debug")),
OPT_END()
};
unsigned opts = parse_opts(argc, argv, program_options, program_usage_string);
argv += optind;
export_abrt_envvars(0);
/* Parse config, extract necessary params */
map_string_t *settings = new_map_string();
char *local_conf = NULL;
if (!conf_file)
{
conf_file = g_list_append(conf_file, (char*) CONF_DIR"/plugins/rhtsupport.conf");
local_conf = xasprintf("%s"USER_HOME_CONFIG_PATH"/rhtsupport.conf", getenv("HOME"));
conf_file = g_list_append(conf_file, local_conf);
}
while (conf_file)
{
const char *fn = (char *)conf_file->data;
log_notice("Loading settings from '%s'", fn);
load_conf_file(fn, settings, /*skip key w/o values:*/ false);
log_debug("Loaded '%s'", fn);
conf_file = g_list_remove(conf_file, fn);
}
free(local_conf);
char *url = get_param_string("URL" , settings, "https://api.access.redhat.com/rs");
char *login = get_param_string("Login" , settings, "");
char *password = get_param_string("Password" , settings, "");
char *bigurl = get_param_string("BigFileURL", settings, "ftp://dropbox.redhat.com/incoming/");
if (login[0] == '\0')
{
free(login);
login = ask_rh_login(_("Login is not provided by configuration. Please enter your RHTS login:"));
}
if (password[0] == '\0')
{
free(password);
char *question = xasprintf(_("Password is not provided by configuration. Please enter the password for '%s':"), login);
password = ask_rh_password(question);
free(question);
}
char* envvar;
envvar = getenv("RHTSupport_SSLVerify");
bool ssl_verify = string_to_bool(
envvar ? envvar : (get_map_string_item_or_NULL(settings, "SSLVerify") ? : "1")
);
envvar = getenv("RHTSupport_BigSizeMB");
unsigned bigsize = xatoi_positive(
/* RH has a 250m limit for web attachments (as of 2013) */
envvar ? envvar : (get_map_string_item_or_NULL(settings, "BigSizeMB") ? : "200")
);
free_map_string(settings);
char *base_api_url = xstrdup(url);
if (opts & OPT_t)
{
if (!case_no)
{
/* -t: extract URL where we previously reported it */
report_result_t *reported_to = get_reported_to(dump_dir_name);
if (reported_to && reported_to->url)
{
free(url);
url = reported_to->url;
reported_to->url = NULL;
free_report_result(reported_to);
char *msg = xasprintf(
_("We found a similar Red Hat support case %s. "
"Do you want to attach the data to the case? "
"Otherwise, you will have to enter the existing "
"Red Hat support case number."), url);
int yes = ask_yes_no(msg);
free(msg);
if (!yes)
url = ask_case_no_create_url(url);
}
else
{
log_warning("Problem was not reported to Red Hat Support.");
url = ask_case_no_create_url(url);
}
}
else
{
/* -tCASE */
url = create_case_url(url, case_no);
}
if (*argv)
{
/* -t[CASE] FILE: just attach files and exit */
while (*argv)
{
log_warning(_("Attaching '%s' to case '%s'"), *argv, url);
rhts_result_t *result = attach_file_to_case(url,
login,
password,
ssl_verify,
*argv
);
if (result->error)
error_msg_and_die("%s", result->msg);
log_warning("Attachment URL:%s", result->url);
log_warning("File attached successfully");
free_rhts_result(result);
argv++;
}
return 0;
}
}
else /* no -t: creating a new case */
{
if (*argv)
show_usage_and_die(program_usage_string, program_options);
report_result_t *reported_to = get_reported_to(dump_dir_name);
if (reported_to && reported_to->url && !(opts & OPT_f))
{
char *msg = xasprintf("This problem was already reported to RHTS (see '%s')."
" Do you still want to create a RHTSupport ticket?",
reported_to->url);
int yes = ask_yes_no(msg);
free(msg);
if (!yes)
return 0;
}
free_report_result(reported_to);
}
problem_data_t *problem_data = create_problem_data_for_reporting(dump_dir_name);
if (!problem_data)
xfunc_die(); /* create_problem_data_for_reporting already emitted error msg */
const char *errmsg = NULL;
char tmpdir_name[sizeof(LARGE_DATA_TMP_DIR"/rhtsupport-"LIBREPORT_ISO_DATE_STRING_SAMPLE"-XXXXXX")];
snprintf(tmpdir_name, sizeof(tmpdir_name), LARGE_DATA_TMP_DIR"/rhtsupport-%s-XXXXXX", iso_date_string(NULL));
/* mkdtemp does mkdir(xxx, 0700), should be safe (is it?) */
if (mkdtemp(tmpdir_name) == NULL)
{
error_msg_and_die(_("Can't create a temporary directory in "LARGE_DATA_TMP_DIR));
}
/* Starting from here, we must perform cleanup on errors
* (delete temp dir)
*/
char *tempfile = NULL;
tempfile = concat_path_basename(tmpdir_name, dump_dir_name);
tempfile = append_to_malloced_string(tempfile, ".tar.gz");
rhts_result_t *result = NULL;
rhts_result_t *result_atch = NULL;
const char *package;
package = problem_data_get_content_or_NULL(problem_data, FILENAME_PACKAGE);
const char *dsc = NULL;
const char *summary = NULL;
const char *count = NULL;
count = problem_data_get_content_or_NULL(problem_data, FILENAME_COUNT);
if (count != NULL
&& strcmp(count, "1") == 0
/* the 'count' file can lie */
&& get_problem_data_reproducible(problem_data) <= PROBLEM_REPRODUCIBLE_UNKNOWN)
{
int r = ask_yes_no(
_("The problem has only occurred once and the ability to reproduce "
"the problem is unknown. Please ensure you will be able to "
"provide detailed information to our Support Team. "
"Would you like to continue and open a new support case?"));
if (!r)
exit(EXIT_CANCEL_BY_USER);
}
const char *vendor = NULL;
vendor = problem_data_get_content_or_NULL(problem_data, FILENAME_PKG_VENDOR);
if (package && vendor && strcmp(vendor, "Red Hat, Inc.") != 0)
{
char *message = xasprintf(
_("The crashed program was released by '%s'. "
"Would you like to report the problem to Red Hat Support?"),
vendor);
int r = ask_yes_no(message);
free(message);
if (!r)
exit(EXIT_CANCEL_BY_USER);
}
/* In the case there is no pkg_vendor file use "unknown vendor" */
if (!vendor)
problem_data_add_text_noteditable(problem_data, FILENAME_PKG_VENDOR, "unknown vendor");
const char *executable = NULL;
executable = problem_data_get_content_or_NULL(problem_data, FILENAME_EXECUTABLE);
if (!package)
{
char *message = xasprintf(
_("The program '%s' does not appear to be provided by Red Hat. "
"Would you like to report the problem to Red Hat Support?"),
executable);
int r = ask_yes_no(message);
free(message);
if (!r)
exit(EXIT_CANCEL_BY_USER);
problem_data_add_text_noteditable(problem_data, FILENAME_PACKAGE,
"not belong to any package");
}
problem_formatter_t *pf = problem_formatter_new();
/* formatting conf file was set */
if (fmt_file)
{
if (problem_formatter_load_file(pf, fmt_file))
error_msg_and_die("Invalid format file: %s", fmt_file);
}
/* using formatting template */
else
{
if (problem_formatter_load_string(pf, PROBLEM_REPORT_TEMPLATE))
error_msg_and_die("Invalid problem report format string");
}
problem_report_t *pr = NULL;
if (problem_formatter_generate_report(pf, problem_data, &pr))
error_msg_and_die("Failed to format bug report from problem data");
/* Add information about attachments into the description */
problem_report_buffer *dsc_buffer = problem_report_get_buffer(pr, PR_SEC_DESCRIPTION);
char *tarball_name = basename(tempfile);
problem_report_buffer_printf(dsc_buffer,
"\n"
"sosreport and other files were attached as '%s' to the case.\n"
"For more details about elements collected by ABRT see:\n"
"%s\n"
, tarball_name, ABRT_ELEMENTS_KB_ARTICLE);
summary = problem_report_get_summary(pr);
dsc = problem_report_get_description(pr);
/* debug */
if (opts & OPT_D)
{
printf("summary: %s\n"
"\n"
"%s"
"\n"
, summary
, dsc
);
problem_report_free(pr);
problem_formatter_free(pf);
exit(0);
}
/* Gzipping e.g. 0.5gig coredump takes a while. Let user know what we are doing */
log_warning(_("Compressing data"));
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
xfunc_die(); /* error msg is already logged by dd_opendir */
if (create_tarball(tempfile, dd, problem_data) != 0)
{
errmsg = _("Can't create temporary file in "LARGE_DATA_TMP_DIR);
goto ret;
}
off_t tempfile_size = stat_st_size_or_die(tempfile);
if (!(opts & OPT_t))
{
if (tempfile_size <= QUERY_HINTS_IF_SMALLER_THAN)
{
/* Check for hints and show them if we have something */
log_warning(_("Checking for hints"));
if (check_for_hints(base_api_url, &login, &password, ssl_verify, tempfile))
goto ret;
}
log_warning(_("Creating a new case"));
char *product = NULL;
char *version = NULL;
map_string_t *osinfo = new_map_string();
problem_data_get_osinfo(problem_data, osinfo);
parse_osinfo_for_rhts(osinfo, &product, &version);
free_map_string(osinfo);
if (!product)
{ /* How can we help user sorting out this problem? */
error_msg_and_die(_("Can't determine RH Support Product from problem data."));
}
INVALID_CREDENTIALS_LOOP(login, password,
result, create_new_case(url, login, password, ssl_verify,
product, version, summary, dsc, package)
);
free(version);
free(product);
problem_report_free(pr);
problem_formatter_free(pf);
if (result->error)
{
/*
* Message can contain "...server says: 'multi-line <html> text'"
* Replace all '\n' with spaces:
* we want this message to be, logically, one log entry.
* IOW: one line, not many lines.
*/
char *src, *dst;
errmsg = dst = src = result->msg;
while (1)
{
unsigned char c = *src++;
if (c == '\n')
c = ' ';
*dst++ = c;
if (c == '\0')
break;
}
/* Remove trailing spaces (usually produced by trailing '\n') */
while (--dst >= errmsg && *dst == ' ')
*dst = '\0';
goto ret;
}
/* No error in case creation */
/* Record "reported_to" element */
dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (dd)
{
struct report_result rr = { .label = (char *)"RHTSupport" };
rr.url = result->url;
rr.msg = result->msg;
time(&rr.timestamp);
add_reported_to_entry(dd, &rr);
dd_close(dd);
if (result->msg)
log_warning("%s", result->msg);
log_warning("URL=%s", result->url);
}
/* else: error msg was already emitted by dd_opendir */
url = result->url;
result->url = NULL;
free_rhts_result(result);
result = NULL;
}
char *remote_filename = NULL;
if (bigsize != 0 && tempfile_size / (1024*1024) >= bigsize)
{
/* Upload tarball of -d DIR to "big file" FTP */
/* log_warning(_("Uploading problem data to '%s'"), bigurl); - upload_file does this */
remote_filename = upload_file(bigurl, tempfile);
}
if (remote_filename)
{
log_warning(_("Adding comment to case '%s'"), url);
/*
* Do not translate message below - it goes
* to a server where *other people* will read it.
*/
char *comment_text = xasprintf(
"Problem data was uploaded to %s",
remote_filename
);
free(remote_filename);
INVALID_CREDENTIALS_LOOP(login, password,
result_atch, add_comment_to_case(url, login, password, ssl_verify, comment_text)
);
free(comment_text);
}
else
{
/* Attach the tarball of -d DIR */
log_warning(_("Attaching problem data to case '%s'"), url);
INVALID_CREDENTIALS_LOOP(login, password,
result_atch, attach_file_to_case(url, login, password, ssl_verify, tempfile)
);
}
if (result_atch->error)
{
if (!(opts & OPT_t))
{
/* Prepend "Case created" text to whatever error message there is,
* so that user knows that case _was_ created despite error in attaching.
*/
log_warning("Case created but failed to attach problem data: %s", result_atch->msg);
}
else
{
log_warning("Failed to attach problem data: %s", result_atch->msg);
}
}
ret:
unlink(tempfile);
free(tempfile);
rmdir(tmpdir_name);
/* Note: errmsg may be = result->msg, don't move this code block
* below free_rhts_result(result)!
*/
if (errmsg)
error_msg_and_die("%s", errmsg);
free_rhts_result(result_atch);
free_rhts_result(result);
free(base_api_url);
free(url);
free(login);
free(password);
problem_data_free(problem_data);
return 0;
}