diff --git a/src/plugins/abrt-retrace-client.c b/src/plugins/abrt-retrace-client.c index a19300e..80c77e7 100644 --- a/src/plugins/abrt-retrace-client.c +++ b/src/plugins/abrt-retrace-client.c @@ -58,6 +58,9 @@ static bool ssl_allow_insecure = false; static bool http_show_headers = false; static unsigned delay = 0; +static int max_formats = 15; +static int max_releases = 31; + static void alert_server_error() { alert(_("An error occured on the server side. Try again later.")); @@ -505,8 +508,9 @@ static char *tcp_read_response(PRFileDesc *tcp_sock) return strbuf_free_nobuf(strbuf); } -static void get_settings(struct retrace_settings *settings) +struct retrace_settings *get_settings() { + struct retrace_settings *settings = xmalloc(sizeof(struct retrace_settings)); /* defaults */ settings->running_tasks = 0; settings->max_running_tasks = 0; @@ -583,11 +587,53 @@ static void get_settings(struct retrace_settings *settings) settings->max_unpacked_size = atoi(value) * 1024 * 1024; else if (0 == strcasecmp("supported_formats", row)) { - /* ToDo */ + /* skip multiple lines with same prefix */ + if (settings->supported_formats) + { + row = c + 1; + continue; + } + + settings->supported_formats = xmalloc((max_formats + 1) * sizeof(char *)); + settings->supported_formats[max_formats] = NULL; + + char *space; + int i; + for (i = 0; i < max_formats && (space = strchr(value, ' ')) != NULL; ++i) + { + *space = '\0'; + settings->supported_formats[i] = xstrdup(value); + value = space + 1; + } + + /* last element */ + settings->supported_formats[i] = xstrdup(value); + settings->supported_formats[++i] = NULL; } else if (0 == strcasecmp("supported_releases", row)) { - /* ToDo */ + /* skip multiple lines with same prefix */ + if (settings->supported_releases) + { + row = c + 1; + continue; + } + + settings->supported_releases = xmalloc((max_releases + 1) * sizeof(char *)); + settings->supported_releases[max_releases] = NULL; + + char *space; + int i; + for (i = 0; i < max_releases && (space = strchr(value, ' ')) != NULL; ++i) + { + *space = '\0'; + settings->supported_releases[i] = xstrdup(value); + value = space + 1; + } + + /* last element */ + settings->supported_releases[i] = xstrdup(value); + settings->supported_releases[++i] = NULL; } /* the beginning of the next row */ @@ -596,6 +642,85 @@ static void get_settings(struct retrace_settings *settings) free(http_response); ssl_disconnect(ssl_sock); + + return settings; +} + +static void free_settings(struct retrace_settings *settings) +{ + if (!settings) + return; + + int i; + if (settings->supported_formats) + for (i = 0; i < max_formats && settings->supported_formats[i]; ++i) + free(settings->supported_formats[i]); + + if (settings->supported_releases) + for (i = 0; i < max_releases && settings->supported_releases[i]; ++i) + free(settings->supported_releases[i]); + + free(settings); +} + +/* dirty, dirty, dirty */ +/* returns release identifier as dist-ver-arch */ +/* or NULL if unknown */ +static char *get_release(const char *dump_dir_name) +{ + char *filename; + FILE *f; + + filename = concat_path_file(dump_dir_name, FILENAME_ARCHITECTURE); + f = fopen(filename, "r"); + free(filename); + if (!f) + perror_msg_and_die("fopen"); + + char *arch = xmalloc_fgetline(f); + fclose(f); + + if (strcmp("i686", arch) == 0 || strcmp("i586", arch) == 0) + { + free(arch); + arch = xstrdup("i386"); + } + + filename = concat_path_file(dump_dir_name, FILENAME_OS_RELEASE); + f = fopen(filename, "r"); + free(filename); + if (!f) + perror_msg_and_die("fopen"); + + char *line = xmalloc_fgetline(f); + char *version = line; + fclose(f); + while (*version && !isdigit(*version)) + ++version; + + if (!*version) + return NULL; + + char *result = NULL; + if (strcasestr(line, "fedora") != NULL) + { + int ver; + if (sscanf(version, "%d", &ver) != 1) + return NULL; + + result = xasprintf("fedora-%d-%s", ver, arch); + } + else if (strcasestr(line, "red hat enterprise linux") != NULL) + { + int maj, min; + if (sscanf(version, "%d.%d", &maj, &min) != 2) + return NULL; + + result = xasprintf("rhel-%d.%d-%s", maj, min, arch); + } + + free(arch); + return result; } static int create(bool delete_temp_archive, @@ -611,10 +736,9 @@ static int create(bool delete_temp_archive, fflush(stdout); } - struct retrace_settings settings; - get_settings(&settings); + struct retrace_settings *settings = get_settings(); - if (settings.running_tasks >= settings.max_running_tasks) + if (settings->running_tasks >= settings->max_running_tasks) { alert(_("The server is fully occupied. Try again later.")); error_msg_and_die(_("The server denied your request.")); @@ -652,13 +776,57 @@ static int create(bool delete_temp_archive, } } - if (unpacked_size > settings.max_unpacked_size) + if (unpacked_size > settings->max_unpacked_size) { alert_crash_too_large(); error_msg_and_die(_("The size of your crash is %lld bytes, " "but the retrace server only accepts " "crashes smaller or equal to %lld bytes."), - unpacked_size, settings.max_unpacked_size); + unpacked_size, settings->max_unpacked_size); + } + + if (settings->supported_formats) + { + int i; + bool supported = false; + for (i = 0; i < max_formats && settings->supported_formats[i]; ++i) + if (strcmp("application/x-xz-compressed-tar", settings->supported_formats[i]) == 0) + { + supported = true; + break; + } + + if (!supported) + { + alert_server_error(); + error_msg_and_die(_("The server does not support " + "xz-compressed tarballs.")); + } + } + + /* we need dump dir to parse release file */ + if (dump_dir_name && settings->supported_releases) + { + char *release = get_release(dump_dir_name); + if (!release) + error_msg_and_die("Unable to parse release."); + int i; + bool supported = false; + for (i = 0; i < max_releases && settings->supported_releases[i]; ++i) + if (strcmp(release, settings->supported_releases[i]) == 0) + { + supported = true; + break; + } + + if (!supported) + { + alert_server_error(); + error_msg_and_die(_("The server does not support " + "release %s."), release); + } + + free(release); } if (delay) @@ -673,16 +841,18 @@ static int create(bool delete_temp_archive, /* Get the file size. */ fstat(tempfd, &file_stat); - if ((long long)file_stat.st_size > settings.max_packed_size) + if ((long long)file_stat.st_size > settings->max_packed_size) { alert_crash_too_large(); error_msg_and_die(_("The size of your archive is %lld bytes, " "but the retrace server only accepts " "archives smaller or equal %lld bytes."), (long long)file_stat.st_size, - settings.max_packed_size); + settings->max_packed_size); } + free_settings(settings); + int size_mb = file_stat.st_size / (1024 * 1024); if (size_mb > 8) /* 8 MB - should be configurable */