[PATCH] trac#641 : abrt-gui displays 'N/A' string instead of empty lines
by Jakub Filak
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gui-gtk/main.c | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/src/gui-gtk/main.c b/src/gui-gtk/main.c
index 12b14e9..87c8205 100644
--- a/src/gui-gtk/main.c
+++ b/src/gui-gtk/main.c
@@ -153,6 +153,19 @@ static void watch_this_dir(const char *dir_name)
}
}
+/* Returns non 0 if str is NULL or if str consists from white spaces */
+static int is_null_or_mepty_string(const char *str)
+{
+ if (!str)
+ return 1;
+
+ while(*str)
+ if (!isspace(*str++))
+ return 0;
+
+ return 1;
+}
+
static void add_directory_to_dirlist(const char *problem_dir_path, gpointer data)
{
bool use_dbus = (bool)data;
@@ -192,15 +205,25 @@ static void add_directory_to_dirlist(const char *problem_dir_path, gpointer data
time_buf[time_len] = '\0';
}
- const char *not_reportable_reason = problem_data_get_content_or_NULL(pd, FILENAME_NOT_REPORTABLE);
- const char *reason = problem_data_get_content_or_NULL(pd, FILENAME_REASON);
+ const char *reason = problem_data_get_content_or_NULL(pd, FILENAME_NOT_REPORTABLE);
+ if (is_null_or_mepty_string(reason)) /* if problem is NOT not reportable we use reason */
+ {
+ reason = problem_data_get_content_or_NULL(pd, FILENAME_REASON);
+ if (is_null_or_mepty_string(reason)) /* if we don't have reason we use 'N/A' */
+ reason = "N/A";
+ }
/* the source of the problem:
* - first we try to load component, as we use it on Fedora
*/
const char *source = problem_data_get_content_or_NULL(pd, FILENAME_COMPONENT);
- if (!source) /* if we don't have component, we fallback to executable */
+ if (is_null_or_mepty_string(source)) /* if we don't have component, we fallback to executable */
+ {
source = problem_data_get_content_or_NULL(pd, FILENAME_EXECUTABLE);
+ if (is_null_or_mepty_string(source)) /* even if we don't have executable, we use 'N/A' */
+ source = "N/A";
+ }
+
const char *msg = problem_data_get_content_or_NULL(pd, FILENAME_REPORTED_TO);
GtkListStore *list_store = s_dumps_list_store;
@@ -215,7 +238,7 @@ static void add_directory_to_dirlist(const char *problem_dir_path, gpointer data
gtk_list_store_append(list_store, &iter);
gtk_list_store_set(list_store, &iter,
COLUMN_SOURCE, source,
- COLUMN_REASON, not_reportable_reason ? : reason,
+ COLUMN_REASON, reason,
//OPTION: time format
COLUMN_LATEST_CRASH_STR, time_buf,
COLUMN_LATEST_CRASH, t,
--
1.7.10.4
11 years, 8 months
[PATCH] trac#622 : introduction of event chain in report-cli
by Jakub Filak
* naive implementation of running of event chain in report-cli
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/cli/cli-report.c | 223 ++++++++++++++++++++++++++++++++++++++------------
src/cli/cli-report.h | 1 +
src/cli/cli.c | 34 ++++----
3 files changed, 187 insertions(+), 71 deletions(-)
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
index 988bfc7..e204435 100644
--- a/src/cli/cli-report.c
+++ b/src/cli/cli-report.c
@@ -520,10 +520,30 @@ static char *do_log_and_save_line(char *log_line, void *param)
l_state->last_line = log_line;
return NULL;
}
+
+static int run_event(struct run_event_state *state, const char *dump_dir_name,
+ const char *event, struct logging_state *l_state)
+{
+ // Export overridden settings as environment variables
+ GList *env_list = export_event_config(event);
+
+ int r = run_event_on_dir_name(state, dump_dir_name, event);
+ if (r == 0 && state->children_count == 0)
+ {
+ l_state->last_line = xasprintf("Error: no processing is specified for event '%s'",
+ event);
+ r = -1;
+ }
+
+ // Unexport overridden settings
+ unexport_event_config(env_list);
+
+ return r;
+}
+
static int run_events(const char *dump_dir_name, GList *events, const char *event_type)
{
int error_cnt = 0;
- GList *env_list = NULL;
// Run events
struct logging_state l_state;
@@ -534,18 +554,7 @@ static int run_events(const char *dump_dir_name, GList *events, const char *even
for (GList *li = events; li; li = li->next)
{
char *event = (char *) li->data;
-
- // Export overridden settings as environment variables
- env_list = export_event_config(event);
-
- int r = run_event_on_dir_name(run_state, dump_dir_name, event);
- if (r == 0 && run_state->children_count == 0)
- {
- l_state.last_line = xasprintf("Error: no processing is specified for event '%s'",
- event);
- r = -1;
- }
- if (r == 0)
+ if (run_event(run_state, dump_dir_name, event, &l_state) == 0)
{
printf("%s: ", event);
if (l_state.last_line)
@@ -560,14 +569,11 @@ static int run_events(const char *dump_dir_name, GList *events, const char *even
event,
l_state.last_line ? ": " : "",
l_state.last_line ? l_state.last_line : ""
- );
- error_cnt++;
+ );
+ ++error_cnt;
}
free(l_state.last_line);
l_state.last_line = NULL;
-
- // Unexport overridden settings
- unexport_event_config(env_list);
}
free_run_event_state(run_state);
@@ -742,6 +748,51 @@ int collect(const char *dump_dir_name, int batch)
return errors;
}
+static int review_problem_data(const char *dump_dir_name, problem_data_t *problem_data)
+{
+ /* Open text editor and give a chance to review the backtrace etc */
+ create_fields_for_editor(problem_data);
+ int result = run_report_editor(problem_data);
+ if (result != 0)
+ return 1;
+
+ /* Save comment, backtrace */
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (dd)
+ {
+ //TODO: we should iterate through problem_data and modify all modifiable fields
+ const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
+ const char *backtrace = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
+ if (comment)
+ dd_save_text(dd, FILENAME_COMMENT, comment);
+ if (backtrace)
+ dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
+ dd_close(dd);
+ }
+
+ return 0;
+}
+
+static int is_backtrace_rating_usable(event_config_t *config, problem_data_t *problem_data)
+{
+ char *usability_description = NULL;
+ char *usability_detail = NULL;
+ const bool usable_rating = check_problem_rating_usability(config, problem_data,
+ &usability_description,
+ &usability_detail);
+
+ if (!usable_rating)
+ {
+ printf("%s\n", usability_description);
+ printf("%s\n", usability_detail);
+ }
+
+ free(usability_description);
+ free(usability_detail);
+
+ return usable_rating;
+}
+
/* Report the crash */
int report(const char *dump_dir_name, int flags)
{
@@ -804,30 +855,12 @@ int report(const char *dump_dir_name, int flags)
problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
dd_close(dd);
- if (!(flags & (CLI_REPORT_BATCH)))
+ if (!(flags & (CLI_REPORT_BATCH))
+ && review_problem_data(dump_dir_name, problem_data))
{
- /* Open text editor and give a chance to review the backtrace etc */
- create_fields_for_editor(problem_data);
- int result = run_report_editor(problem_data);
- if (result != 0)
- {
- problem_data_free(problem_data);
- free(report_events_as_lines);
- return 1;
- }
- /* Save comment, backtrace */
- dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
- if (dd)
- {
-//TODO: we should iterate through problem_data and modify all modifiable fields
- const char *comment = problem_data_get_content_or_NULL(problem_data, FILENAME_COMMENT);
- const char *backtrace = problem_data_get_content_or_NULL(problem_data, FILENAME_BACKTRACE);
- if (comment)
- dd_save_text(dd, FILENAME_COMMENT, comment);
- if (backtrace)
- dd_save_text(dd, FILENAME_BACKTRACE, backtrace);
- dd_close(dd);
- }
+ problem_data_free(problem_data);
+ free(report_events_as_lines);
+ return 1;
}
/* Get possible reporters associated with this particular crash */
@@ -885,17 +918,8 @@ int report(const char *dump_dir_name, int flags)
if (!is_number_in_string(i, wanted_reporters))
continue;
- char *usability_description = NULL;
- char *usability_detail = NULL;
- const bool usable_rating = check_problem_rating_usability(config, problem_data,
- &usability_description,
- &usability_detail);
-
- if (!usable_rating)
+ if (!is_backtrace_rating_usable(config, problem_data))
{
- printf("%s\n", usability_description);
- printf("%s\n", usability_detail);
-
errors++;
goto next_plugin;
}
@@ -914,8 +938,6 @@ int report(const char *dump_dir_name, int flags)
next_plugin:
plugins++;
- free(usability_description);
- free(usability_detail);
}
}
@@ -924,3 +946,98 @@ next_plugin:
list_free_with_free(report_events);
return errors;
}
+
+struct chain_logging_param
+{
+ struct logging_state l_state;
+ bool terminate;
+};
+
+static char *do_log_and_terminate_chain_on_request(char *log_line, void *param)
+{
+ struct chain_logging_param *arg = (struct chain_logging_param *)param;
+
+ arg->terminate = strcmp("THANKYOU", log_line) == 0;
+
+ return do_log_and_save_line(log_line, &(arg->l_state));
+}
+
+/*
+ * Runs event from chain. Perform the following steps for each event from chain.
+ * 1. Terminates a chain run if a backtrace is not usable.
+ * 2. Asks for missing settings.
+ * 3. Performs review of problem data if event requires review.
+ * 4. Runs events commands.
+ * 5. Terminates a chain run if any event from the chain requires termination
+ * (prints THANKYOU to stdout in the current implementation)
+ * 6. Terminates a chain run if any error occurs.
+ * 7. Continues immediately with processing of next event.
+ */
+int run_events_chain(const char *dump_dir_name, GList *chain)
+{
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ if (!dd)
+ return -1;
+
+ problem_data_t *problem_data = create_problem_data_from_dump_dir(dd);
+
+ dd_close(dd);
+
+ struct chain_logging_param chain_state = {
+ .l_state = {
+ .last_line = NULL,
+ },
+ .terminate = false,
+ };
+
+ struct run_event_state *run_state = new_run_event_state();
+ run_state->logging_callback = do_log_and_terminate_chain_on_request;
+ run_state->logging_param = &chain_state;
+
+ int returncode = 0;
+
+ for (GList *eitem = chain; !chain_state.terminate && eitem; eitem = g_list_next(eitem))
+ {
+ const char *const event = (const char *)eitem->data;
+ event_config_t *config = get_event_config(event);
+
+ if (!is_backtrace_rating_usable(config, problem_data))
+ /* it is not a failure of event if the backtrace is unusable */
+ break;
+
+ if (config)
+ {
+ /* can't fail */
+ ask_for_missing_settings(event);
+
+ /* review problem data only if the event needs it */
+ if (!config->ec_skip_review
+ && review_problem_data(dump_dir_name, problem_data))
+ {
+ /* review failed, an error message was already logged */
+ returncode = -1;
+ break;
+ }
+ }
+
+ returncode = run_event(run_state, dump_dir_name, event, &chain_state.l_state);
+ if (returncode != 0)
+ {
+ error_msg("'%s' event was not successful%s%s",
+ event,
+ chain_state.l_state.last_line ? ": " : "",
+ chain_state.l_state.last_line ? chain_state.l_state.last_line : ""
+ );
+ break;
+ }
+
+ free(chain_state.l_state.last_line);
+ chain_state.l_state.last_line = NULL;
+ }
+
+ free_run_event_state(run_state);
+ free(chain_state.l_state.last_line);
+ problem_data_free(problem_data);
+
+ return returncode;
+}
diff --git a/src/cli/cli-report.h b/src/cli/cli-report.h
index b34293d..8dd3773 100644
--- a/src/cli/cli-report.h
+++ b/src/cli/cli-report.h
@@ -32,6 +32,7 @@ enum {
};
int report(const char *dump_dir_name, int flags);
int collect(const char *dump_dir_name, int batch);
+int run_events_chain(const char *dump_dir_name, GList *chain);
#ifdef __cplusplus
}
diff --git a/src/cli/cli.c b/src/cli/cli.c
index 66ebbe2..5a221ad 100644
--- a/src/cli/cli.c
+++ b/src/cli/cli.c
@@ -23,10 +23,18 @@
#include "internal_libreport.h"
#include "cli-report.h"
-static char *do_log(char *log_line, void *param)
+static char *steal_directory_if_needed(char *dump_dir_name)
{
- log("%s", log_line);
- return log_line;
+ struct dump_dir *dd = open_directory_for_writing(dump_dir_name,
+ /* ask callback */ NULL);
+
+ if (dd)
+ {
+ dump_dir_name = xstrdup(dd->dd_dirname);
+ dd_close(dd);
+ }
+
+ return dump_dir_name;
}
int main(int argc, char** argv)
@@ -47,7 +55,7 @@ int main(int argc, char** argv)
textdomain(PACKAGE);
#endif
- const char *event_name = NULL;
+ GList *event_list = NULL;
const char *pfx = "";
/* Can't keep these strings/structs static: _() doesn't support that */
@@ -77,7 +85,7 @@ int main(int argc, char** argv)
struct options program_options[] = {
/* short_name long_name value parameter_name help */
OPT_OPTSTRING('L', NULL , &pfx, "PREFIX", _("List possible events [which start with PREFIX]")),
- OPT_STRING( 'e', NULL , &event_name, "EVENT", _("Run EVENT on DUMP_DIR")),
+ OPT_LIST( 'e', "event" , &event_list, "EVENT", _("Run only these events")),
OPT_BOOL( 'a', "analyze", NULL, _("Run analyze event(s) on DUMP_DIR")),
OPT_BOOL( 'c', "collect", NULL, _("Run collect event(s) on DUMP_DIR")),
OPT_BOOL( 'r', "report" , NULL, _("Analyze, collect and report problem data in DUMP_DIR")),
@@ -144,12 +152,8 @@ int main(int argc, char** argv)
}
case OPT_run_event: /* -e EVENT: run event */
{
- struct run_event_state *run_state = new_run_event_state();
- run_state->logging_callback = do_log;
- int r = run_event_on_dir_name(run_state, dump_dir_name, event_name);
- if (r == 0 && run_state->children_count == 0)
- error_msg_and_die("No actions are found for event '%s'", event_name);
- free_run_event_state(run_state);
+ dump_dir_name = steal_directory_if_needed(dump_dir_name);
+ exitcode = run_events_chain(dump_dir_name, event_list);
break;
}
case OPT_analyze:
@@ -184,13 +188,7 @@ int main(int argc, char** argv)
}
case OPT_report:
{
- struct dump_dir *dd = open_directory_for_writing(dump_dir_name, NULL);
-
- if (dd)
- {
- dump_dir_name = xstrdup(dd->dd_dirname);
- dd_close(dd);
- }
+ dump_dir_name = steal_directory_if_needed(dump_dir_name);
exitcode = report(dump_dir_name,
(always ? CLI_REPORT_BATCH : 0));
--
1.7.10.4
11 years, 8 months
[PATCH] trac#645: abrtd: do not run post-create event concurrently
by Jakub Filak
* concurrent run of post-create event may mark all processed problems as
duplicates of each other and delete all of them
* abrtd accepts notifications and pushes a problem directory to a queue
* after processing of one problem abrtd pops a directory from the queue
and continues of processing with next directory
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/daemon/abrtd.c | 66 ++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/src/daemon/abrtd.c b/src/daemon/abrtd.c
index 1112591..c664a66 100644
--- a/src/daemon/abrtd.c
+++ b/src/daemon/abrtd.c
@@ -74,6 +74,24 @@ static int child_count = 0;
*/
static GList *s_pid_list;
+/*
+ * The post-create event cannot be run concurrently for more problem
+ * directories. The problem is in searching for duplicates process in case when
+ * two concurrently processed directories are duplicates of each other. Both of
+ * the directories are marked as duplicates of each other and are deleted.
+ *
+ * This queue is used for serialization of processing of created problem
+ * directories.
+ *
+ * The GIO notify handler pushes new directories to this queue and if the queue was
+ * empty before push then starts processing of the pushed directory.
+ *
+ * Directory processing code pops the processed directory from the queue at the
+ * end of processing. If the queue is not empty starts processing of the next
+ * directory which is on the top of the queue.
+ */
+static GList *s_dir_queue;
+
enum {
EVTYPE_POST_CREATE,
EVTYPE_NOTIFY,
@@ -291,6 +309,25 @@ static gboolean handle_signal_cb(GIOChannel *gio, GIOCondition condition, gpoint
return TRUE; /* "please don't remove this event" */
}
+static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr);
+
+/* Runs post-create event asynchronously. Uses GIOChanel for communication with event process. */
+static void run_post_create_on_dir_async(const char *name)
+{
+ struct event_processing_state *state = new_event_processing_state();
+ state->event_type = EVTYPE_POST_CREATE;
+ state->dirname = concat_path_file(g_settings_dump_location, name);
+
+ state->child_pid = spawn_event_handler_child(state->dirname, "post-create", &state->child_stdout_fd);
+ s_pid_list = g_list_prepend(s_pid_list, state);
+ ndelay_on(state->child_stdout_fd);
+
+ GIOChannel *channel_event_output = my_io_channel_unix_new(state->child_stdout_fd);
+ /*uint channel_id_event_output =*/ g_io_add_watch(channel_event_output,
+ G_IO_IN | G_IO_PRI | G_IO_HUP,
+ handle_event_output_cb,
+ state);
+}
/* Event-processing child output handler (such as "post-create" event) */
static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr)
@@ -435,11 +472,21 @@ static gboolean handle_event_output_cb(GIOChannel *gio, GIOCondition condition,
/* We stop using this channel */
g_io_channel_unref(gio);
+
+ /* pop the currently processed directory from the incoming queue */
+ char *name = s_dir_queue->data;
+ s_dir_queue = g_list_remove(s_dir_queue, name);
+ free(name);
+
+ /* if the queue is not empty process directory from */
+ /* the top of the incoming queue */
+ if (s_dir_queue)
+ run_post_create_on_dir_async(s_dir_queue->data);
+
return FALSE; /* "glib, please remove this events source!" */
/* Removing will also drop the last ref to this gio, closing/freeing it */
}
-
/* Inotify handler */
static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpointer ptr_unused)
@@ -550,19 +597,14 @@ static gboolean handle_inotify_cb(GIOChannel *gio, GIOCondition condition, gpoin
}
}
- struct event_processing_state *state = new_event_processing_state();
- state->event_type = EVTYPE_POST_CREATE;
- state->dirname = concat_path_file(g_settings_dump_location, name);
+ const bool empty_queue = s_dir_queue == NULL;
+ /* push the new directory to the end of the incoming queue */
+ s_dir_queue = g_list_append(s_dir_queue, xstrdup(name));
- state->child_pid = spawn_event_handler_child(state->dirname, "post-create", &state->child_stdout_fd);
- s_pid_list = g_list_prepend(s_pid_list, state);
- ndelay_on(state->child_stdout_fd);
+ /* if the queue was empty process the current directory */
+ if (empty_queue)
+ run_post_create_on_dir_async(name);
- GIOChannel *channel_event_output = my_io_channel_unix_new(state->child_stdout_fd);
- /*uint channel_id_event_output =*/ g_io_add_watch(channel_event_output,
- G_IO_IN | G_IO_PRI | G_IO_HUP,
- handle_event_output_cb,
- state);
} /* while */
free(buf);
--
1.7.10.4
11 years, 9 months
[PATCH] strcmp: change !strcmp to more readable strcmp == 0
by Nikola Pajkovsky
Signed-off-by: Nikola Pajkovsky <npajkovs(a)redhat.com>
---
src/gtk-helpers/event_config_dialog.c | 5 +++--
src/lib/json.c | 6 +++---
src/lib/make_descr.c | 3 ++-
src/lib/proxies.c | 2 +-
src/plugins/rhbz.c | 6 +++---
src/report-newt/report-newt.c | 2 +-
6 files changed, 13 insertions(+), 11 deletions(-)
diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c
index 190dad1..0125f02 100644
--- a/src/gtk-helpers/event_config_dialog.c
+++ b/src/gtk-helpers/event_config_dialog.c
@@ -355,7 +355,7 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent)
/*x,yoptions:*/ GTK_FILL, GTK_FILL,
/*x,ypadding:*/ 0, 0);
const char *store_passwords = get_user_setting("store_passwords");
- if (store_passwords && !strcmp(store_passwords, "no"))
+ if (store_passwords && strcmp(store_passwords, "no") == 0)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pass_store_cb), 1);
g_signal_connect(pass_store_cb, "toggled", G_CALLBACK(on_show_pass_store_cb), NULL);
}
@@ -389,7 +389,8 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent)
const char *const store_passwords_s = get_user_setting("store_passwords");
save_event_config_data_to_user_storage(event_name,
get_event_config(event_name),
- !(store_passwords_s && !strcmp(store_passwords_s, "no")));
+ !(store_passwords_s && strcmp(store_passwords_s,
+ "no") == 0));
}
//else if (result == GTK_RESPONSE_CANCEL)
// log("log");
diff --git a/src/lib/json.c b/src/lib/json.c
index 2cda77d..e2bfe35 100644
--- a/src/lib/json.c
+++ b/src/lib/json.c
@@ -102,11 +102,11 @@ static void ureport_add_type(struct json_object *ur, problem_data_t *pd)
if (!pd_item)
return;
- if (!strcmp(pd_item, "CCpp"))
+ if (strcmp(pd_item, "CCpp") == 0)
ureport_add_str(ur, "type", "USERSPACE");
- if (!strcmp(pd_item, "Python"))
+ if (strcmp(pd_item, "Python") == 0)
ureport_add_str(ur, "type", "PYTHON");
- if (!strcmp(pd_item, "Kerneloops"))
+ if (strcmp(pd_item, "Kerneloops") == 0)
ureport_add_str(ur, "type", "KERNELOOPS");
}
diff --git a/src/lib/make_descr.c b/src/lib/make_descr.c
index c8c0f71..585fe4e 100644
--- a/src/lib/make_descr.c
+++ b/src/lib/make_descr.c
@@ -189,7 +189,8 @@ char *make_description(problem_data_t *problem_data, char **names_to_skip,
if ((item->flags & CD_FLAG_TXT)
&& (strlen(item->content) <= max_text_size
- || (!strcmp(analyzer, "Kerneloops") && !strcmp(key, FILENAME_BACKTRACE))))
+ || (strcmp(analyzer, "Kerneloops") == 0 && strcmp(key,
+ FILENAME_BACKTRACE) == 0)))
{
char *formatted = problem_item_format(item);
char *output = make_description_item_multiline(key, formatted ? formatted : item->content);
diff --git a/src/lib/proxies.c b/src/lib/proxies.c
index b52be91..10b11c0 100644
--- a/src/lib/proxies.c
+++ b/src/lib/proxies.c
@@ -48,7 +48,7 @@ GList *get_proxy_list(const char *url)
free(proxies);
/* Don't set proxy if the list contains just "direct://" */
- if (l && !g_list_next(l) && !strcmp(l->data, "direct://"))
+ if (l && !g_list_next(l) && strcmp(l->data, "direct://") == 0)
{
list_free_with_free(l);
l = NULL;
diff --git a/src/plugins/rhbz.c b/src/plugins/rhbz.c
index 905660b..d65ce65 100644
--- a/src/plugins/rhbz.c
+++ b/src/plugins/rhbz.c
@@ -192,7 +192,7 @@ int is_comment_dup(GList *comments, const char *comment)
{
const char * const comment_body = (const char *) l->data;
char * const trim_comment_body = trim_all_whitespace(comment_body);
- same_comments = !strcmp(trim_comment_body, trim_comment);
+ same_comments = strcmp(trim_comment_body, trim_comment) == 0;
free(trim_comment_body);
}
@@ -836,7 +836,7 @@ int rhbz_attach_files(struct abrt_xmlrpc *ax, const char *bug_id,
const char *analyzer = problem_data_get_content_or_NULL(problem_data,
FILENAME_ANALYZER);
/* Do not attach anything if analyzer is Kerneloops */
- if (!strcmp(analyzer, "Kerneloops"))
+ if (strcmp(analyzer, "Kerneloops") == 0)
return 0;
GHashTableIter iter;
@@ -858,7 +858,7 @@ int rhbz_attach_files(struct abrt_xmlrpc *ax, const char *bug_id,
const unsigned len = strlen(content);
/* For standard bugs, do not attach backtrace shorter than CD_TEXT_ATT_SIZE_BZ */
- if (!strcmp(name, FILENAME_BACKTRACE) && len < CD_TEXT_ATT_SIZE_BZ)
+ if (strcmp(name, FILENAME_BACKTRACE) == 0 && len < CD_TEXT_ATT_SIZE_BZ)
continue;
rhbz_attach_blob(ax, name, bug_id, content, len, flags);
diff --git a/src/report-newt/report-newt.c b/src/report-newt/report-newt.c
index 6287445..318ff10 100644
--- a/src/report-newt/report-newt.c
+++ b/src/report-newt/report-newt.c
@@ -128,7 +128,7 @@ static int configure_reporter(struct reporter *r, bool skip_if_valid)
break;
case OPTION_TYPE_BOOL:
options[i] = newtCheckbox(0, 0, "", opt->eo_value &&
- !strcmp(opt->eo_value, "yes") ? '*' : ' ', NULL, NULL);
+ strcmp(opt->eo_value, "yes") == 0 ? '*' : ' ', NULL, NULL);
break;
default: /* TODO? */
options[i] = NULL;
--
1.7.10.2
11 years, 9 months
[PATCH] trac#621 : terminate processing of an event chain on a request
by Jakub Filak
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/gui-wizard-gtk/wizard.c | 8 +++++++-
src/plugins/ureport.c | 4 ++--
2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index c93ff42..8591cad 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -1300,6 +1300,13 @@ static void run_event_gtk_error(const char *error_line, void *param)
static char *run_event_gtk_logging(char *log_line, void *param)
{
update_command_run_log(log_line, (struct analyze_event_data *)param);
+
+ if (!strcmp(log_line, "THANKYOU"))
+ {
+ VERB1 log("Received a request for termination of processing of event chain. (Request: '%s')", log_line);
+ g_auto_event_list = NULL;
+ }
+
return log_line;
}
@@ -1592,7 +1599,6 @@ static void start_event_run(const char *event_name,
);
gtk_label_set_text(status_label, start_msg);
-
VERB1 log("running event '%s' on '%s'", event_name, g_dump_dir_name);
char *msg = xasprintf("--- Running %s ---\n", event_name);
append_to_textview(evd->tv_log, msg);
diff --git a/src/plugins/ureport.c b/src/plugins/ureport.c
index 13d1c9e..a504285 100644
--- a/src/plugins/ureport.c
+++ b/src/plugins/ureport.c
@@ -166,8 +166,8 @@ int main(int argc, char **argv)
VERB1 log("is known: %s", response.value);
ret = 0;
/* If a reported problem is not known then emit NEEDMORE */
- if (strcmp("true",response.value))
- log("NEEDMORE");
+ if (!strcmp("true", response.value))
+ log("THANKYOU");
break;
case UREPORT_SERVER_RESP_ERROR:
VERB1 log("server side error: %s", response.value);
--
1.7.10.4
11 years, 9 months
[PATCH 1/2] trac#622 : move bt rating check to a library function
by Jakub Filak
* unification of implementaion of report-gtk and report-cli
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/cli/cli-report.c | 29 ++++++++---------
src/gui-wizard-gtk/wizard.c | 55 +++++---------------------------
src/include/event_config.h | 22 +++++++++++++
src/lib/event_config.c | 73 +++++++++++++++++++++++++++++++++++++++++++
4 files changed, 117 insertions(+), 62 deletions(-)
diff --git a/src/cli/cli-report.c b/src/cli/cli-report.c
index 117c6fb..988bfc7 100644
--- a/src/cli/cli-report.c
+++ b/src/cli/cli-report.c
@@ -857,12 +857,7 @@ int report(const char *dump_dir_name, int flags)
}
else
{
- const char *rating_str = problem_data_get_content_or_NULL(problem_data, FILENAME_RATING);
-//COMPAT, remove after 2.1 release
- if (!rating_str)
- rating_str = problem_data_get_content_or_NULL(problem_data, "rating");
-
- unsigned i, rating = rating_str ? xatou(rating_str) : 4;
+ unsigned i;
GList *li;
char wanted_reporters[255];
@@ -890,18 +885,21 @@ int report(const char *dump_dir_name, int flags)
if (!is_number_in_string(i, wanted_reporters))
continue;
- if (config && (rating < config->ec_minimal_rating))
- {
- puts(_("Reporting disabled because the backtrace is unusable"));
+ char *usability_description = NULL;
+ char *usability_detail = NULL;
+ const bool usable_rating = check_problem_rating_usability(config, problem_data,
+ &usability_description,
+ &usability_detail);
- const char *package = problem_data_get_content_or_NULL(problem_data, FILENAME_PACKAGE);
- if (package && package[0])
- printf(_("Please try to install debuginfo manually using the command: \"debuginfo-install %s\" and try again\n"), package);
+ if (!usable_rating)
+ {
+ printf("%s\n", usability_description);
+ printf("%s\n", usability_detail);
- plugins++;
errors++;
- continue;
+ goto next_plugin;
}
+
ask_for_missing_settings(reporter_name);
/*
@@ -914,7 +912,10 @@ int report(const char *dump_dir_name, int flags)
errors += run_events(dump_dir_name, cur_event, "Reporting");
g_list_free(cur_event);
+next_plugin:
plugins++;
+ free(usability_description);
+ free(usability_detail);
}
}
diff --git a/src/gui-wizard-gtk/wizard.c b/src/gui-wizard-gtk/wizard.c
index c93ff42..a32aafa 100644
--- a/src/gui-wizard-gtk/wizard.c
+++ b/src/gui-wizard-gtk/wizard.c
@@ -1644,61 +1644,20 @@ static bool check_minimal_bt_rating(const char *event_name)
if (!event_name)
error_msg_and_die(_("Cannot check backtrace rating because of invalid event name"));
- else if(strncmp("report", event_name, sizeof("report")-1) != 0)
+ else if (prefixcmp(event_name, "report") != 0)
{
- VERB1 log("No checks for bactrace rating because event '%s' doesn't report.", event_name);
+ VERB2 log("No checks for bactrace rating because event '%s' doesn't report.", event_name);
return acceptable_rating;
}
else
- {
event_cfg = get_event_config(event_name);
- if (!event_cfg)
- {
- VERB1 log("Cannot check backtrace rating because of not defined configuration for event '%s'", event_name);
- return acceptable_rating;
- }
- }
-
- /*
- * FIXME: this should be bind to a reporter not to a compoment
- * but so far only oopses don't have rating, so for now we
- * skip the "kernel" manually
- */
- const char *analyzer = problem_data_get_content_or_NULL(g_cd, FILENAME_ANALYZER);
-//FIXME: say "no" to special casing!
- if (event_cfg && analyzer && strcmp(analyzer, "Kerneloops") != 0)
+ char *description = NULL;
+ acceptable_rating = check_problem_rating_usability(event_cfg, g_cd, &description, NULL);
+ if (description)
{
- const char *rating_str = problem_data_get_content_or_NULL(g_cd, FILENAME_RATING);
-//COMPAT, remove after 2.1 release
- if (!rating_str)
- rating_str = problem_data_get_content_or_NULL(g_cd, "rating");
-
- if (rating_str)
- {
- char *endptr;
- errno = 0;
- long rating = strtol(rating_str, &endptr, 10);
- if (errno != 0 || endptr == rating_str || *endptr != '\0')
- {
- add_warning(_("Reporting disabled because the rating does not contain a number."));
- acceptable_rating = false;
- }
- else
- {
- VERB1 log("Checking current rating %ld to required rating %ld.", rating, event_cfg->ec_minimal_rating);
- if (rating == event_cfg->ec_minimal_rating) /* bt is usable, but not complete, so show a warning */
- {
- add_warning(_("The backtrace is incomplete, please make sure you provide the steps to reproduce."));
- }
- else if (rating < event_cfg->ec_minimal_rating)
- {
- add_warning(_("Reporting disabled because the backtrace is unusable."));
- //FIXME: see CreporterAssistant: 394 for ideas
- acceptable_rating = false;
- }
- }
- }
+ add_warning(description);
+ free(description);
}
return acceptable_rating;
diff --git a/src/include/event_config.h b/src/include/event_config.h
index 6644b42..15ebf52 100644
--- a/src/include/event_config.h
+++ b/src/include/event_config.h
@@ -21,6 +21,7 @@
#include <stdbool.h>
#include <glib.h>
+#include "problem_data.h"
#ifdef __cplusplus
extern "C" {
@@ -103,6 +104,27 @@ void unexport_event_config(GList *env_list);
GHashTable *validate_event(const char *event_name);
+/*
+ * Checks usability of problem's backtrace rating against required rating level
+ * from event configuration.
+ *
+ * @param cfg an event configuration
+ * @param pd a checked problem data
+ * @param description an output parameter for a description of rating
+ * usability. If the variable holds NULL after function call no description is
+ * available. The description can be provided even if backtrace rating is
+ * acceptable. Can be NULL.
+ * @param detail an output parameter for a more details about rating usability.
+ * If the variable holds NULL after function call no description is available.
+ * The detail can be provided even if backtrace rating is acceptable. Can be
+ * NULL.
+ * @returns true if rating is usable or above usable; otherwise false
+ */
+bool check_problem_rating_usability(const event_config_t *cfg,
+ problem_data_t *pd,
+ char **description,
+ char **detail);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/lib/event_config.c b/src/lib/event_config.c
index 85c0e80..9bf0d5f 100644
--- a/src/lib/event_config.c
+++ b/src/lib/event_config.c
@@ -367,3 +367,76 @@ GHashTable *validate_event(const char *event_name)
return NULL;
}
+
+/*
+ * This function checks if a value of problem's backtrace rating is acceptable
+ * for event according to event's required rating value.
+ *
+ * The solved problem seems to be pretty straightforward but there are some
+ * pitfalls.
+ *
+ * 1. Is rating acceptable if event doesn't have configuration?
+ * 2. Is rating acceptable if problem's data doesn't contains rating value?
+ * 3. Is rating acceptable if rating value is not a number?
+ * 4. What message show to user if there is a concern about usability?
+ */
+bool check_problem_rating_usability(const event_config_t *cfg,
+ problem_data_t *pd,
+ char **description,
+ char **detail)
+{
+ char *tmp_desc = NULL;
+ char *tmp_detail = NULL;
+
+ bool result = false;
+
+ const char *rating_str = problem_data_get_content_or_NULL(pd, FILENAME_RATING);
+ if (!cfg || !rating_str)
+ goto finish;
+
+ const long minimal_rating = cfg->ec_minimal_rating;
+ char *endptr;
+ errno = 0;
+ const long rating = strtol(rating_str, &endptr, 10);
+ if (errno != 0 || endptr == rating_str || *endptr != '\0')
+ {
+ tmp_desc = xasprintf("%s '%s'.", _("Reporting disabled because the rating does not contain a number."), rating_str);
+ tmp_detail = xstrdup(_("Please report this problem to ABRT."));
+
+ result = false;
+ }
+ else if (rating == minimal_rating) /* bt is usable, but not complete, so show a warning */
+ {
+ tmp_desc = xstrdup(_("The backtrace is incomplete, please make sure you provide the steps to reproduce."));
+ tmp_detail = xstrdup(_("The backtrace probably can't help to a developer in searching for bug."));
+
+ result = true;
+ }
+ else if (rating < minimal_rating)
+ {
+ tmp_desc = xstrdup(_("Reporting disabled because the backtrace is unusable."));
+
+ const char *package = problem_data_get_content_or_NULL(pd, FILENAME_PACKAGE);
+ if (package && package[0])
+ tmp_detail = xasprintf(_("Please try to install debuginfo manually using the command: \"debuginfo-install %s\" and try again."), package);
+ else
+ tmp_detail = xstrdup(_("A proppert debuginfo is probably missing or the coredump is corrupted."));
+
+ result = false;
+ }
+ else /* rating > minimal_rating */
+ result = true;
+
+finish:
+ if (description)
+ *description = tmp_desc;
+ else
+ free(tmp_desc);
+
+ if (detail)
+ *detail = tmp_detail;
+ else
+ free(tmp_detail);
+
+ return result;
+}
--
1.7.10.4
11 years, 9 months
[PATCH v5] track#549 : gnome-keyring replaced by Secret Service API
by Jakub Filak
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
configure.ac | 1 +
libreport.spec.in | 7 -
src/gtk-helpers/Makefile.am | 6 +-
src/gtk-helpers/abrt-keyring.c | 130 ----
src/gtk-helpers/event_config_dialog.c | 71 +--
src/gtk-helpers/internal_libreport_gtk.h | 15 +-
src/gtk-helpers/secrets.c | 1050 ++++++++++++++++++++++++++++++
src/gui-wizard-gtk/main.c | 2 +-
8 files changed, 1072 insertions(+), 210 deletions(-)
delete mode 100644 src/gtk-helpers/abrt-keyring.c
create mode 100644 src/gtk-helpers/secrets.c
diff --git a/configure.ac b/configure.ac
index 25d44e5..06896a9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,6 +82,7 @@ AC_SUBST(XMLRPC_CLIENT_LIBS)
PKG_CHECK_MODULES([GTK], [gtk+-3.0])
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.21])
+PKG_CHECK_MODULES([GIO], [gio-2.0])
PKG_CHECK_MODULES([DBUS], [dbus-1])
PKG_CHECK_MODULES([LIBXML], [libxml-2.0])
PKG_CHECK_MODULES([NSS], [nss])
diff --git a/libreport.spec.in b/libreport.spec.in
index f65c87d..ebe247a 100644
--- a/libreport.spec.in
+++ b/libreport.spec.in
@@ -35,13 +35,6 @@ Requires: libreport-filesystem
# FIXME: can be removed when F15 will EOLed, needs to stay in rhel6!
Requires: libreport-python
-# for rhel6
-%if 0%{?rhel} >= 6
-BuildRequires: gnome-keyring-devel
-%else
-BuildRequires: libgnome-keyring-devel
-%endif
-
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
%description
diff --git a/src/gtk-helpers/Makefile.am b/src/gtk-helpers/Makefile.am
index 188e48f..68ec928 100644
--- a/src/gtk-helpers/Makefile.am
+++ b/src/gtk-helpers/Makefile.am
@@ -10,7 +10,7 @@ lib_LTLIBRARIES = \
libreport_gtk_la_SOURCES = \
event_config_dialog.c \
- abrt-keyring.c \
+ secrets.c \
hyperlinks.c \
autowrapped_label.c
@@ -20,14 +20,14 @@ libreport_gtk_la_CPPFLAGS = \
-I$(srcdir)/../lib \
$(GTK_CFLAGS) \
$(GLIB_CFLAGS) \
- $(GNOME_KEYRING_CFLAGS) \
+ $(GIO_CFLAGS) \
-D_GNU_SOURCE
libreport_gtk_la_LDFLAGS = \
-version-info 0:1:0
libreport_gtk_la_LIBADD = \
$(GTK_LIBS) \
$(GLIB_LIBS) \
- $(GNOME_KEYRING_LIBS) \
+ $(GIO_LIBS) \
../lib/libreport.la
EXTRA_DIST = libreport-gtk.pc.in
diff --git a/src/gtk-helpers/abrt-keyring.c b/src/gtk-helpers/abrt-keyring.c
deleted file mode 100644
index 4e830ca..0000000
--- a/src/gtk-helpers/abrt-keyring.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- Copyright (C) 2011 ABRT Team
- Copyright (C) 2011 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 <gnome-keyring.h>
-#include "internal_libreport.h"
-#include "internal_libreport_gtk.h"
-
-static char *keyring_name;
-static bool got_keyring = 0;
-bool g_keyring_available = 1; //by default we assume that keyring is available
-
-guint32 find_keyring_item_id_for_event(const char *event_name)
-{
- GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
- GList *found = NULL;
- gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig", event_name);
- GnomeKeyringResult result = gnome_keyring_find_items_sync(
- GNOME_KEYRING_ITEM_GENERIC_SECRET,
- attrs,
- &found);
- gnome_keyring_attribute_list_free(attrs);
-
- //let's hope 0 is not valid item_id
- guint32 item_id = 0;
- if (result != GNOME_KEYRING_RESULT_OK)
- goto ret;
- if (found)
- item_id = ((GnomeKeyringFound *)found->data)->item_id;
- ret:
- if (found)
- gnome_keyring_found_list_free(found);
- VERB2 log("keyring has %sconfiguration for event '%s'", (item_id != 0) ? "" : "no ", event_name);
- return item_id;
-}
-
-static void abrt_keyring_load_settings(const char *event_name, event_config_t *ec)
-{
- //don't bother when we already know that keyring is not available
- if (!g_keyring_available)
- return;
-
- guint item_id = find_keyring_item_id_for_event(event_name);
- if (!item_id)
- return;
- GnomeKeyringAttributeList *attrs = NULL;
- GnomeKeyringResult result = gnome_keyring_item_get_attributes_sync(
- keyring_name,
- item_id,
- &attrs);
- if (result == GNOME_KEYRING_RESULT_OK && attrs)
- {
- VERB3 log("num attrs %i", attrs->len);
- guint index;
- for (index = 0; index < attrs->len; index++)
- {
- char *name = g_array_index(attrs, GnomeKeyringAttribute, index).name;
- VERB2 log("keyring has name '%s'", name);
- event_option_t *option = get_event_option_from_list(name, ec->options);
- if (option)
- {
- free(option->eo_value);
- option->eo_value = xstrdup(g_array_index(attrs, GnomeKeyringAttribute, index).value.string);
- VERB2 log("added or replaced in event config:'%s=%s'", name, option->eo_value);
- }
- }
- }
- if (attrs)
- gnome_keyring_attribute_list_free(attrs);
-}
-
-static void init_keyring()
-{
- /* Called again? */
- if (got_keyring || !g_keyring_available)
- return;
-
- if (!gnome_keyring_is_available())
- {
- g_keyring_available = 0;
- VERB1 error_msg("Cannot connect to Gnome keyring daemon");
- return;
- }
-
- GnomeKeyringResult result = gnome_keyring_get_default_keyring_sync(&keyring_name);
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Can't get default keyring (result:%d)", result);
- return;
- }
-
- got_keyring = 1;
- /*
- * Note: The default keyring name can be NULL. It is a valid name.
- */
- VERB2 log("keyring:'%s'", keyring_name);
-}
-
-static void load_event_config(gpointer key, gpointer value, gpointer user_data)
-{
- char* event_name = (char*)key;
- event_config_t *ec = (event_config_t *)value;
- VERB2 log("loading event '%s' configuration from keyring", event_name);
- abrt_keyring_load_settings(event_name, ec);
-}
-
-/*
- * Tries to load settings for all events in g_event_config_list
-*/
-void load_event_config_data_from_keyring(void)
-{
- init_keyring();
- if (!got_keyring)
- return;
- g_hash_table_foreach(g_event_config_list, &load_event_config, NULL);
-}
diff --git a/src/gtk-helpers/event_config_dialog.c b/src/gtk-helpers/event_config_dialog.c
index 5a564fe..190dad1 100644
--- a/src/gtk-helpers/event_config_dialog.c
+++ b/src/gtk-helpers/event_config_dialog.c
@@ -17,7 +17,6 @@
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <gtk/gtk.h>
-#include <gnome-keyring.h>
#include "internal_libreport_gtk.h"
static GtkWindow *g_event_list_window;
@@ -298,63 +297,6 @@ static void dehydrate_config_dialog()
g_list_foreach(option_widget_list, &save_value_from_widget, NULL);
}
-static void save_settings_to_keyring(const char *event_name)
-{
- //don't bother when we already know that keyring is not available
- if (!g_keyring_available)
- return;
- char *keyring_name = NULL;
- GnomeKeyringResult result = gnome_keyring_get_default_keyring_sync(&keyring_name);
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Can't get default keyring (result:%d)", result);
- return;
- }
-
- const char *store_passwords_s = get_user_setting("store_passwords");
- bool store_passwords = !(store_passwords_s && !strcmp(store_passwords_s, "no"));
-
- GnomeKeyringAttributeList *attrs = gnome_keyring_attribute_list_new();
- event_config_t *ec = get_event_config(event_name);
- /* add string id which we use to search for items */
- gnome_keyring_attribute_list_append_string(attrs, "libreportEventConfig", event_name);
- GList *l;
- for (l = g_list_first(ec->options); l != NULL; l = g_list_next(l))
- {
- event_option_t *op = (event_option_t *)l->data;
- gnome_keyring_attribute_list_append_string(attrs, op->eo_name,
- (!store_passwords && op->eo_type == OPTION_TYPE_PASSWORD) ? "" : op->eo_value);
- }
-
- guint32 item_id = find_keyring_item_id_for_event(event_name);
- if (item_id)
- {
- /* found existing item, so just update the values */
- result = gnome_keyring_item_set_attributes_sync(keyring_name, item_id, attrs);
- VERB2 log("updated item with id: %i", item_id);
- }
- else
- {
- /* did't find existing item, so create a new one */
- result = gnome_keyring_item_create_sync(keyring_name,
- GNOME_KEYRING_ITEM_GENERIC_SECRET, /* type */
- event_name, /* display name */
- attrs, /* attributes */
- "", /* secret - no special handling for password it's stored in attrs */
- 1, /* update if exist */
- &item_id);
- VERB2 log("created new item with id: %i", item_id);
- }
- gnome_keyring_attribute_list_free(attrs);
-
- if (result != GNOME_KEYRING_RESULT_OK)
- {
- error_msg("Error saving event '%s' configuration to keyring", event_name);
- return;
- }
- VERB2 log("saved event '%s' configuration to keyring", event_name);
-}
-
int show_event_config_dialog(const char *event_name, GtkWindow *parent)
{
if (option_widget_list != NULL)
@@ -425,14 +367,14 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent)
if (g_list_length(gtk_container_get_children(GTK_CONTAINER(g_adv_option_table))) > 0)
gtk_box_pack_start(GTK_BOX(content), adv_expander, false, false, 0);
- /* add warning if keyring is not available showing the nagging dialog
+ /* add warning if secrets service is not available showing the nagging dialog
* is considered "too heavy UI" be designers
*/
- if (!g_keyring_available)
+ if (!is_event_config_user_storage_available())
{
GtkWidget *keyring_warn_lbl =
gtk_label_new(
- _("Gnome Keyring is not available, your settings won't be saved!"));
+ _("Secret Service is not available, your settings won't be saved!"));
static const GdkColor red = { .red = 0xffff };
gtk_widget_modify_fg(keyring_warn_lbl, GTK_STATE_NORMAL, &red);
gtk_box_pack_start(GTK_BOX(content), keyring_warn_lbl, false, false, 0);
@@ -444,7 +386,10 @@ int show_event_config_dialog(const char *event_name, GtkWindow *parent)
if (result == GTK_RESPONSE_APPLY)
{
dehydrate_config_dialog();
- save_settings_to_keyring(event_name);
+ const char *const store_passwords_s = get_user_setting("store_passwords");
+ save_event_config_data_to_user_storage(event_name,
+ get_event_config(event_name),
+ !(store_passwords_s && !strcmp(store_passwords_s, "no")));
}
//else if (result == GTK_RESPONSE_CANCEL)
// log("log");
@@ -460,7 +405,7 @@ void show_events_list_dialog(GtkWindow *parent)
if (g_event_config_list == NULL)
{
load_event_config_data();
- load_event_config_data_from_keyring();
+ load_event_config_data_from_user_storage(g_event_config_list);
}
GtkWidget *event_list_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
diff --git a/src/gtk-helpers/internal_libreport_gtk.h b/src/gtk-helpers/internal_libreport_gtk.h
index 092bfad..dd9ff87 100644
--- a/src/gtk-helpers/internal_libreport_gtk.h
+++ b/src/gtk-helpers/internal_libreport_gtk.h
@@ -27,19 +27,22 @@
extern "C" {
#endif
-extern bool g_keyring_available;
-
#define make_label_autowrap_on_resize libreport_make_label_autowrap_on_resize
void make_label_autowrap_on_resize(GtkLabel *label);
#define show_events_list_dialog libreport_show_events_list_dialog
void show_events_list_dialog(GtkWindow *parent);
-#define load_event_config_data_from_keyring libreport_load_event_config_data_from_keyring
-void load_event_config_data_from_keyring(void);
+#define is_event_config_user_storage_available libreport_is_event_config_user_storage_available
+bool is_event_config_user_storage_available();
+
+#define load_event_config_data_from_user_storage libreport_load_event_config_data_from_user_storage
+void load_event_config_data_from_user_storage(GHashTable *event_config_list);
-#define find_keyring_item_id_for_event libreport_find_keyring_item_id_for_event
-guint32 find_keyring_item_id_for_event(const char *event_name);
+#define save_event_config_data_to_user_storage libreport_save_event_config_data_to_user_storage
+void save_event_config_data_to_user_storage(const char *event_name,
+ const event_config_t *event_config,
+ bool store_password);
#define show_event_config_dialog libreport_show_event_config_dialog
int show_event_config_dialog(const char *event_name, GtkWindow *parent);
diff --git a/src/gtk-helpers/secrets.c b/src/gtk-helpers/secrets.c
new file mode 100644
index 0000000..29f3ee3
--- /dev/null
+++ b/src/gtk-helpers/secrets.c
@@ -0,0 +1,1050 @@
+/*
+ Copyright (C) 2012 ABRT Team
+ Copyright (C) 2012 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 "internal_libreport.h"
+#include "internal_libreport_gtk.h"
+
+#include <gio/gio.h>
+
+#define secrets_api "org.freedesktop.secrets"
+#define SECRETS_NAME_SPACE(interface) "org.freedesktop.Secret."interface
+
+/* label and alias have to be same because of ksecrets */
+#define SECRETS_COLLECTION_LABEL SECRETS_COLLECTION_ALIAS
+#define SECRETS_COLLECTION_ALIAS "default"
+
+#define SECRETS_SEARCH_ATTRIBUTE "libreportEventConfig"
+
+/* 5s timeout*/
+#define SECRETS_CALL_DEFAULT_TIMEOUT 5000
+
+/* Well known errors for which we have workarounds */
+#define NOT_IMPLEMENTED_READ_ALLIAS_ERROR_MESSAGE "GDBus.Error:org.freedesktop.DBus.Error.UnknownMethod: No such method 'ReadAlias' in interface 'org.freedesktop.Secret.Service' at object path '/org/freedesktop/secrets' (signature 's')"
+#define INVALID_PROPERTIES_ARGUMENTS "GDBus.Error:org.freedesktop.DBus.Error.InvalidArgs: Invalid properties argument"
+
+
+enum secrets_api_state
+{
+ /* intial state */
+ SBS_INITIAL = 0,
+ /* after opening a secrets service session (different than D-Bus session) */
+ SBS_CONNECTED,
+ /* secrets service is not available do not bother user anymore */
+ SBS_UNAVAILABLE,
+};
+
+struct secrets_object
+{
+ GDBusProxy *proxy;
+ /* http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfac... */
+ GDBusProxy *property_proxy;
+ const gchar *interface_name;
+};
+
+/* Glib DBus object org.freedesktop.secrets */
+GDBusConnection *g_connection;
+
+/* State of the service */
+enum secrets_api_state g_state;
+
+/* http://standards.freedesktop.org/secret-service/re01.html */
+/* xorg.freedesktop.Secret.Service interface object */
+struct secrets_object *g_service;
+
+/* http://standards.freedesktop.org/secret-service/ch06.html */
+/* xorg.freedesktop.Secret.Session interface object */
+GDBusProxy *g_session;
+
+/*******************************************************************************/
+/* struct secrets_object */
+/*******************************************************************************/
+
+static struct secrets_object *secrets_object_new_from_proxy(GDBusProxy *proxy)
+{
+ struct secrets_object *obj = xmalloc(sizeof(*obj));
+ obj->proxy = proxy;
+ obj->property_proxy = NULL;
+ obj->interface_name = g_dbus_proxy_get_interface_name(proxy);
+
+ return obj;
+}
+
+static struct secrets_object *secrets_object_new(const gchar *path,
+ const gchar *interface,
+ GError **error)
+{
+ GDBusProxy *const proxy =
+ g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ secrets_api, path, interface, NULL, error);
+
+ if (*error)
+ return NULL;
+
+ return secrets_object_new_from_proxy(proxy);
+}
+
+static void secrets_object_change_path(struct secrets_object *obj,
+ const gchar *path,
+ GError **error)
+{
+ GDBusProxy *const proxy =
+ g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ secrets_api, path, obj->interface_name, NULL, error);
+
+ if (!*error)
+ {
+ if (obj->proxy)
+ g_object_unref(obj->proxy);
+
+ obj->proxy = proxy;
+ obj->interface_name = g_dbus_proxy_get_interface_name(proxy);
+ }
+}
+
+static void secrets_object_delete(struct secrets_object *obj)
+{
+ if (obj->proxy)
+ g_object_unref(obj->proxy);
+
+ if (obj->property_proxy)
+ g_object_unref(obj->property_proxy);
+
+ free(obj);
+}
+
+static GDBusProxy *secrets_object_get_properties_proxy(struct secrets_object *obj, GError **error)
+{
+ if (!obj->property_proxy)
+ {
+ obj->property_proxy
+ = g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ secrets_api, g_dbus_proxy_get_object_path(obj->proxy),
+ "org.freedesktop.DBus.Properties", NULL, error);
+
+ if (*error)
+ return NULL;
+ }
+
+ return obj->property_proxy;
+}
+
+
+static void secrets_object_set_dbus_property(struct secrets_object *obj,
+ const char *property,
+ GVariant *value,
+ GError **error)
+{
+ GDBusProxy *properties = secrets_object_get_properties_proxy(obj, error);
+
+ if (!*error)
+ {
+ GVariant *const ret
+ = g_dbus_proxy_call_sync(properties, "Set",
+ g_variant_new("(ssv)", obj->interface_name, property, value),
+ G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT, NULL,
+ error);
+
+ if (ret)
+ g_variant_unref(ret);
+ }
+}
+
+/*******************************************************************************/
+/* struct secrets_api */
+/*******************************************************************************/
+
+static void secrets_api_set_unavailable();
+
+static void secrets_api_error(GError* error, const char *comment)
+{
+ if (comment)
+ {
+ log("%s : %s\n", comment, error->message);
+ }
+ else
+ {
+ log("%s\n", error->message);
+ }
+
+ g_error_free(error);
+ secrets_api_set_unavailable();
+}
+
+/*
+ * Initialize all global variables
+ */
+static enum secrets_api_state secrets_api_connect()
+{
+ GError *error = NULL;
+
+ g_connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, &error);
+
+ if (g_connection == NULL)
+ {
+ secrets_api_error(error, "failed to open connection to D-Bus session");
+ return SBS_UNAVAILABLE;
+ }
+
+ g_service = secrets_object_new("/org/freedesktop/secrets", SECRETS_NAME_SPACE("Service"), &error);
+ if (error)
+ {
+ secrets_api_error(error, "failed to create service");
+ return SBS_UNAVAILABLE;
+ }
+
+ GVariant *const alg_in = g_variant_new_string("");
+ GVariant *const args = g_variant_new("(sv)", "plain", alg_in);
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(g_service->proxy, "OpenSession", args, G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT, NULL, &error);
+
+ g_variant_unref(alg_in);
+
+ if (error)
+ {
+ secrets_api_error(error, "cannot open session Secrets session");
+ return SBS_UNAVAILABLE;
+ }
+
+ GVariant *const var = g_variant_get_child_value(ret, 1);
+ g_variant_unref(ret);
+
+ const gchar *const session_path = g_variant_get_string(var, NULL);
+ g_session = g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL, secrets_api,
+ session_path, SECRETS_NAME_SPACE("Session"), NULL, &error);
+
+ g_variant_unref(var);
+
+ if (error)
+ {
+ secrets_api_error(error, "cannot create Proxy for Secrets session");
+ return SBS_UNAVAILABLE;
+ }
+
+ g_state = SBS_CONNECTED;
+
+ return g_state;
+}
+
+static void secrets_api_init()
+{
+ if (g_state == SBS_INITIAL)
+ secrets_api_connect();
+}
+
+static void secrets_api_close()
+{
+ if (g_state == SBS_INITIAL || g_state == SBS_UNAVAILABLE)
+ return;
+
+ GError *error = NULL;
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(g_session, "Close", g_variant_new("()"), G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT, NULL, &error);
+
+ if (error)
+ {
+ VERB1 log("error on closing Secrets session : %s\n", error->message);
+ g_error_free(error);
+ }
+ else
+ g_variant_unref(ret);
+
+ g_object_unref(g_session);
+
+ secrets_object_delete(g_service);
+
+ g_object_unref(g_connection);
+
+ g_connection = NULL;
+ g_service = NULL;
+ g_session = NULL;
+ g_state = SBS_INITIAL;
+}
+
+static void secrets_api_set_unavailable()
+{
+ secrets_api_close();
+
+ g_state = SBS_UNAVAILABLE;
+}
+
+static int is_secrets_api_available()
+{
+ return g_state != SBS_UNAVAILABLE;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Prompt */
+/* http://standards.freedesktop.org/secret-service/re05.html */
+/*******************************************************************************/
+
+struct prompt_source
+{
+ GSource source;
+ GDBusProxy *prompt_proxy;
+ GError *error;
+ GMainLoop *loop;
+};
+
+struct prompt_call_back_args
+{
+ gboolean dismissed;
+ GVariant *result;
+ GMainLoop *loop;
+};
+
+static void prompt_quit_loop(GMainLoop* loop)
+{
+ if (g_main_loop_is_running(loop))
+ g_main_loop_quit(loop);
+}
+
+static gboolean prompt_g_idle_prepare(GSource *source_data, gint *timeout)
+{
+ return TRUE;
+}
+
+static gboolean prompt_g_idle_check(GSource *source)
+{
+ return TRUE;
+}
+
+static gboolean prompt_g_idle_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ struct prompt_source *const prompt_source = (struct prompt_source *)source;
+ GDBusProxy *const prompt_proxy = prompt_source->prompt_proxy;
+ GVariant *const args = g_variant_new("(s)","");
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(prompt_proxy, "Prompt", args, G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT, NULL, &prompt_source->error);
+
+ if (prompt_source->error)
+ prompt_quit_loop(prompt_source->loop);
+ else
+ g_variant_unref(ret);
+
+ /* always return FALSE, it means that this dispatch is to be removed from idle loop */
+ return FALSE;
+}
+
+static void prompt_call_back(GDBusConnection *connection, const gchar *sender_name,
+ const gchar *object_path, const gchar *interface_name,
+ const gchar *signal_name, GVariant *parameters,
+ gpointer user_data)
+{
+ struct prompt_call_back_args *const args = (struct prompt_call_back_args *)user_data;
+ GVariant *const result = NULL;
+
+ g_variant_get(parameters, "(bv)", &args->dismissed, &result);
+
+ if (!args->dismissed)
+ args->result = result;
+ else
+ g_variant_unref(result);
+
+ prompt_quit_loop(args->loop);
+}
+
+static bool is_prompt_required(const char *prompt_path)
+{
+ return prompt_path && !(prompt_path[0] == '/' && prompt_path[1] == '\0');
+}
+
+static bool secrets_prompt(const char *prompt_path,
+ GVariant **result,
+ GError **error)
+{
+ static GSourceFuncs idle_funcs = {
+ .prepare = prompt_g_idle_prepare,
+ .check = prompt_g_idle_check,
+ .dispatch = prompt_g_idle_dispatch,
+ .finalize = NULL,
+ .closure_callback = NULL,
+ .closure_marshal = NULL,
+ };
+
+ GDBusProxy *const prompt_proxy =
+ g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL, secrets_api,
+ prompt_path, SECRETS_NAME_SPACE("Prompt"), NULL, error);
+
+ if (*error)
+ return true;
+
+ GMainContext *context = g_main_context_get_thread_default();
+ GMainLoop *loop = g_main_loop_new(context, FALSE);
+
+ struct prompt_call_back_args args = {
+ .result=NULL,
+ .dismissed=FALSE,
+ .loop=loop
+ };
+
+ const guint signal_ret =
+ g_dbus_connection_signal_subscribe(g_connection, secrets_api, SECRETS_NAME_SPACE("Prompt"),
+ "Completed", prompt_path, NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+ prompt_call_back, &args, NULL);
+
+ /* prepare prompt source */
+ struct prompt_source *const prompt_source =
+ (struct prompt_source*)g_source_new(&idle_funcs, sizeof(*prompt_source));
+
+ prompt_source->prompt_proxy = prompt_proxy;
+ prompt_source->error = NULL;
+
+ g_source_attach((GSource*)prompt_source, context);
+
+ g_main_loop_run(loop);
+
+ /* save error */
+ *error = prompt_source->error;
+ if (args.result)
+ {
+ if (result)
+ *result = args.result;
+ else
+ g_variant_unref(args.result);
+ }
+
+ /* destroy prompt source */
+ g_object_unref(prompt_proxy);
+ g_source_destroy((GSource*)prompt_source);
+
+ g_dbus_connection_signal_unsubscribe(g_connection, signal_ret);
+ g_main_loop_unref(loop);
+
+ return args.dismissed;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Service */
+/* http://standards.freedesktop.org/secret-service/re01.html */
+/*******************************************************************************/
+
+static bool secrets_service_unlock(const gchar *const *objects,
+ GVariant **unlocked,
+ GError **error)
+{
+ bool dismissed = false;
+ GVariant *const args = g_variant_new("(^ao)", objects);
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(g_service->proxy, "Unlock", args, G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT, NULL, error);
+
+ if (*error)
+ return dismissed;
+
+ gchar *prompt;
+ GVariant *result;
+ g_variant_get(ret, "(@aoo)", &result, &prompt);
+
+ if (is_prompt_required(prompt))
+ {
+ g_variant_unref(result);
+ result = NULL;
+ dismissed = secrets_prompt(prompt, &result, error);
+ }
+
+ if (result)
+ { /* in case of error or dismissed the result variable has NULL value */
+ if (unlocked)
+ *unlocked = result;
+ else
+ g_variant_unref(result);
+ }
+
+ g_variant_unref(ret);
+
+ return dismissed;
+}
+
+static bool secrets_service_unlock_object(struct secrets_object *obj,
+ GError **error)
+{
+ const gchar *const locked[] = {
+ g_dbus_proxy_get_object_path(obj->proxy),
+ NULL
+ };
+
+ GVariant *result = NULL;
+ bool dismissed = secrets_service_unlock(locked, &result, error);
+
+ if (!*error && !dismissed && result)
+ {
+ gsize length;
+ const gchar *const *unlocked = g_variant_get_objv(result, &length);
+
+ /* ksecrets doesn't set dismissed correctly */
+ if (length)
+ {
+ secrets_object_change_path(obj, *unlocked, error);
+ g_free((gpointer)unlocked);
+ }
+ else
+ dismissed = true;
+
+ g_variant_unref(result);
+ }
+
+ return dismissed;
+}
+
+/*
+ * KSecretsService doesn't implement ReadAlias
+ */
+static struct secrets_object *secrets_service_find_collection(const char *alias, GError **error)
+{
+ /* do not unref this proxy, the proxy is owned by secrets object */
+ GDBusProxy *const properties = secrets_object_get_properties_proxy(g_service, error);
+
+ if (*error)
+ return NULL;
+
+ /* cannot use g_dbus_proxy_get_cached_property() because of */
+ /* errors in case when secrets service was restarted during session */
+ GVariant *const prop =
+ g_dbus_proxy_call_sync(properties, "Get",
+ g_variant_new("(ss)", SECRETS_NAME_SPACE("Service"), "Collections"),
+ G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT, NULL, error);
+
+ if (*error)
+ return NULL;
+
+ struct secrets_object *collection = NULL;
+
+ /* Returned value */
+ GVariant *const value = g_variant_get_child_value(prop,0);
+ /* Contentet of returned value */
+ GVariant *const list = g_variant_get_child_value(value,0);
+
+ GVariantIter *iter;
+ char *path;
+ g_variant_get(g_variant_get_child_value(value,0), "ao", &iter);
+
+ while (g_variant_iter_loop(iter, "o", &path))
+ {
+ GDBusProxy *const collection_proxy =
+ g_dbus_proxy_new_sync(g_connection, G_DBUS_PROXY_FLAGS_NONE, NULL, secrets_api,
+ path, SECRETS_NAME_SPACE("Collection"), NULL, error);
+
+ if (*error)
+ break;
+
+ GVariant *const lbl_var = g_dbus_proxy_get_cached_property(collection_proxy,
+ "Label");
+
+ const gchar *const label = g_variant_get_string(lbl_var, NULL);
+ const int found = label && (strcmp(label, alias) == 0);
+
+ /* found is introduced because of break if collecion is found */
+ /* and I want to write the following statement just once */
+ /* the label variable is invalid after the following statement */
+ g_variant_unref(lbl_var);
+
+ if (found)
+ {
+ collection = secrets_object_new_from_proxy(collection_proxy);
+ break;
+ }
+
+ g_object_unref(collection_proxy);
+ }
+
+ g_variant_iter_free(iter);
+ g_variant_unref(list);
+ g_variant_unref(value);
+ g_variant_unref(prop);
+
+ return collection;
+}
+
+static struct secrets_object *secrets_service_read_allias(const char *alias, GError **error)
+{
+ struct secrets_object *collection = NULL;
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(g_service->proxy, "ReadAlias", g_variant_new("(s)", alias),
+ G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL, error);
+
+ if (!*error)
+ {
+ GVariant *const obj_path = g_variant_get_child_value(ret, 0);
+ const gchar* const coll_path = g_variant_get_string(obj_path, NULL);
+
+ if (strcmp(coll_path,"/"))
+ collection = secrets_object_new(coll_path,
+ SECRETS_NAME_SPACE("Collection"),
+ error);
+
+ g_variant_unref(obj_path);
+ g_variant_unref(ret);
+ }
+ else if (!strcmp((*error)->message, NOT_IMPLEMENTED_READ_ALLIAS_ERROR_MESSAGE))
+ {
+ /* ksecrets doesn't implement ReadAlias, thus search by label is performed */
+ VERB1 log("ReadAlias failed, going to search on the client side : %s", (*error)->message);
+ g_error_free(*error);
+ *error = NULL;
+ collection = secrets_service_find_collection(alias, error);
+ }
+
+ return collection;
+}
+
+static struct secrets_object *secrets_service_create_collection(const gchar *label,
+ const gchar *alias,
+ bool *dismissed,
+ GError **error)
+{
+ GVariantBuilder *const prop_builder = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(prop_builder, "{sv}", "org.freedesktop.Secret.Collection.Label",
+ g_variant_new_string(label) );
+
+ GVariant *const call_args =
+ g_variant_new("(@a{sv}s)", g_variant_builder_end(prop_builder), alias);
+
+ GVariant *const ret =
+ g_dbus_proxy_call_sync(g_service->proxy, "CreateCollection", call_args, G_DBUS_PROXY_FLAGS_NONE,
+ SECRETS_CALL_DEFAULT_TIMEOUT, NULL, error);
+
+ *dismissed = false;
+
+ if (*error)
+ return NULL;
+
+ gchar *prompt;
+ GVariant *collection_var;
+ g_variant_get(ret, "(@oo)", &collection_var, &prompt);
+
+ if (is_prompt_required(prompt))
+ {
+ g_variant_unref(collection_var);
+ collection_var = NULL;
+
+ *dismissed = secrets_prompt(prompt, &collection_var, error);
+ }
+
+ struct secrets_object *collection = NULL;
+ if (collection_var)
+ {
+ gsize length;
+ const gchar *const coll_path = g_variant_get_string(collection_var, &length);
+
+ /* ksecrets doens't properly set dismissed */
+ /* if dismissmised is false and result is empty */
+ /* then ksecrets didn't properly set dismissed */
+ if (length)
+ collection = secrets_object_new(coll_path, SECRETS_NAME_SPACE("Collection"), error);
+ else
+ *dismissed = true;
+
+ g_variant_unref(collection_var);
+ }
+
+ g_variant_unref(ret);
+
+ return collection;
+}
+
+/*******************************************************************************/
+/* org.freedesktop.Secret.Collection */
+/* http://standards.freedesktop.org/secret-service/re02.html */
+/*******************************************************************************/
+
+static GVariant *create_item_call_args(const char *event_name,
+ GVariant *attributes,
+ GDBusProxy *session,
+ bool full_property_name)
+{
+ /* ksecrets accepts properties without namespace */
+ /* gnome-keyring accepts only with namespace */
+ const char *const lbl_name = full_property_name ? SECRETS_NAME_SPACE("Item.Label")
+ : "Label";
+ const char *const att_name = full_property_name ? SECRETS_NAME_SPACE("Item.Attributes")
+ : "Attributes";
+
+ GVariantBuilder *const prop_builder = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(prop_builder, "{sv}", lbl_name, g_variant_new_string(event_name));
+ g_variant_builder_add(prop_builder, "{sv}", att_name, attributes);
+
+ GVariantBuilder *const param_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+ GVariantBuilder *const value_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
+
+ GVariant *const secret = g_variant_new("(o@ay@ays)",
+ g_dbus_proxy_get_object_path(session),
+ g_variant_builder_end(param_builder),
+ g_variant_builder_end(value_builder),
+ "text/plain, charset=utf8");
+
+ return g_variant_new("(@a{sv}@(oayays)b)", g_variant_builder_end(prop_builder), secret, FALSE);
+}
+
+static void secrets_collection_create_text_item(struct secrets_object *collection,
+ const char *event_name,
+ GVariant *attributes,
+ GError **error)
+{
+ GVariant *call_args, *ret;
+
+ /* ksecrets silently drops properties with full names */
+ /* gnome-keyring returns an error if a property key is not full property name */
+ /* the first iteration sends property names without namespace */
+ /* if NO error was returned service is ksecrets and everything is ok */
+ /* if error was returned service is gnome-keyring and and the second iteration */
+ /* must be performed */
+ /* the second iteration sends property names with namespace */
+ static bool const options[] = {FALSE, TRUE};
+ for (size_t choice = 0; choice < sizeof(options)/sizeof(*options); ++choice)
+ {
+ if (*error)
+ { /* this code is here because I want to return an error */
+ /* it cannot be on the end of the loop because I need unfreed error after the last iteration */
+ g_error_free(*error);
+ *error = NULL;
+ }
+
+ call_args = create_item_call_args(event_name, g_variant_ref(attributes),
+ g_session, options[choice]);
+
+ ret = g_dbus_proxy_call_sync(collection->proxy, "CreateItem", call_args,
+ G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT,
+ NULL, error);
+
+ if (*error)
+ {
+ if (!strcmp(INVALID_PROPERTIES_ARGUMENTS, (*error)->message))
+ {
+ VERB2 log("CreateItem failed, going to use other properties names : %s", (*error)->message);
+ continue;
+ }
+ else
+ /* if the error wasn't about invalid properties we have an another problem */
+ break;
+ }
+
+ gchar *prompt, *item;
+ g_variant_get(ret, "(oo)", &item, &prompt);
+
+ if (is_prompt_required(prompt))
+ {
+ const bool dismissed = secrets_prompt(prompt, NULL, error);
+ if (*error || dismissed)
+ secrets_api_set_unavailable();
+
+ g_variant_unref(ret);
+ break;
+ }
+
+ g_variant_unref(ret);
+ }
+
+ g_variant_unref(attributes);
+}
+
+/*
+ * Performs org.freedesktop.Secret.Collection.SearchItems and returns the first
+ * item from result. A found item can be possibly locked.
+ */
+static struct secrets_object *secrets_collection_search_one_item(
+ const struct secrets_object *collection,
+ GVariant *search_attrs,
+ GError **error)
+{
+ struct secrets_object *item = NULL;
+ GVariant *const value =
+ g_dbus_proxy_call_sync(collection->proxy, "SearchItems", g_variant_new("(@a{ss})", search_attrs),
+ G_DBUS_PROXY_FLAGS_NONE, SECRETS_CALL_DEFAULT_TIMEOUT, NULL, error);
+
+ if (*error)
+ return NULL;
+
+ /* gnome-keyring returns (unlocked,locked) */
+ /* ksecretsservice returns (unlocked) */
+ /* all childs has to be taken into account */
+ const gsize n_results = g_variant_n_children(value);
+ for(gsize child = 0; !item && child < n_results; ++child)
+ {
+ if (*error)
+ {
+ VERB1 log("search items result error : %s", (*error)->message);
+ free(*error);
+ *error = NULL;
+ }
+
+ GVariant *const paths = g_variant_get_child_value(value, 0);
+ const gchar *const *item_paths = g_variant_get_objv(paths, NULL);
+
+ /* the first found object path is to be returned */
+ if (*item_paths)
+ item = secrets_object_new(*item_paths, SECRETS_NAME_SPACE("Item"), error);
+
+ g_free((gpointer)item_paths);
+ g_variant_unref(paths);
+ }
+
+ g_variant_unref(value);
+
+ return item;
+}
+
+/*******************************************************************************/
+/* utility functions */
+/*******************************************************************************/
+
+static struct secrets_object *get_default_collection(GError **error)
+{
+ bool dismissed = false;
+ struct secrets_object *collection =
+ secrets_service_read_allias(SECRETS_COLLECTION_ALIAS, error);
+
+ if (!*error && collection)
+ {
+ dismissed = secrets_service_unlock_object(collection, error);
+
+ if (*error || dismissed)
+ {
+ secrets_object_delete(collection);
+ collection = NULL;
+ }
+ }
+
+ if (dismissed)
+ /* A user canceled an unlock prompt */
+ /* Secrets BUS is set to unvailable in order to not bother a user */
+ /* with an another unlock prompt */
+ secrets_api_set_unavailable();
+
+ /* no matter if error occured or prompt was dismissed */
+ /* in these cases the collection holds NULL */
+ return collection;
+}
+
+static void load_event_options_from_item(GList *options,
+ struct secrets_object *item)
+{
+ GVariant *const attributes =
+ g_dbus_proxy_get_cached_property(item->proxy, "Attributes");
+
+ GVariantIter *iter;
+ g_variant_get(attributes, "a{ss}", &iter);
+
+ char *name, *value;
+ while (g_variant_iter_loop(iter, "{ss}", &name, &value))
+ {
+ event_option_t *const option = get_event_option_from_list(name, options);
+ if (option)
+ {
+ free(option->eo_value);
+ option->eo_value = xstrdup(value);
+ VERB2 log("loaded event option : '%s => %s'", name, option->eo_value);
+ }
+ }
+
+ g_variant_unref(attributes);
+}
+
+static GVariant *create_attributes_from_options(GList *options,
+ const char *event_name,
+ bool store_passwords)
+{
+ GVariantBuilder *const attr_builder = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ for (GList *iter = g_list_first(options); iter; iter = g_list_next(iter))
+ { /* we store data in the search attributes */
+ event_option_t *const op = (event_option_t *)iter->data;
+ if (op->eo_type != OPTION_TYPE_PASSWORD || store_passwords)
+ g_variant_builder_add(attr_builder, "{ss}", op->eo_name, op->eo_value);
+ }
+
+ /* and finaly, add extra attribute used for searching */
+ g_variant_builder_add(attr_builder, "{ss}", SECRETS_SEARCH_ATTRIBUTE, event_name);
+
+ return g_variant_builder_end(attr_builder);
+}
+
+static struct secrets_object *find_item_by_event_name(const struct secrets_object *collection,
+ const char* event_name,
+ GError **error)
+{
+ GVariantBuilder *const attrs = g_variant_builder_new(G_VARIANT_TYPE_DICTIONARY);
+
+ g_variant_builder_add(attrs, "{ss}", SECRETS_SEARCH_ATTRIBUTE, event_name);
+
+ return secrets_collection_search_one_item(collection, g_variant_builder_end(attrs), error);
+}
+
+static void load_settings(struct secrets_object *collection, const char *event_name, event_config_t *ec)
+{
+ /* Locked property is not supported by ksecrets */
+ /* thus we have to perform Unlock on each call of load settings */
+ /* because a collection can be locked by the service at anytime */
+ GError *error = NULL;
+ const bool dismissed = secrets_service_unlock_object(collection, &error);
+
+ if (!error && !dismissed)
+ {
+ struct secrets_object *item = find_item_by_event_name(collection, event_name, &error);
+
+ if (!error && item)
+ {
+ VERB2 log("loading event config : '%s'", event_name);
+ load_event_options_from_item(ec->options, item);
+ secrets_object_delete(item);
+ }
+ }
+
+ if (dismissed)
+ secrets_api_set_unavailable();
+
+ if (error)
+ secrets_api_error(error, NULL);
+}
+
+static void load_event_config(gpointer key, gpointer value, gpointer user_data)
+{
+ char *const event_name = (char*)key;
+ event_config_t *const ec = (event_config_t *)value;
+ struct secrets_object *collection = (struct secrets_object *)user_data;
+
+ if (is_secrets_api_available())
+ load_settings(collection, event_name, ec);
+}
+
+static void save_options(struct secrets_object *collection,
+ const char* event_name,
+ GList *options,
+ bool store_passwords,
+ GError **error)
+{
+ struct secrets_object *item;
+ item = find_item_by_event_name(collection, event_name, error);
+
+ if (*error)
+ return;
+
+ GVariant *const attributes = create_attributes_from_options(options,
+ event_name,
+ store_passwords);
+
+ if (item)
+ { /* item exists */
+ VERB2 log("updating event config : '%s'", event_name);
+ secrets_object_set_dbus_property(item, "Attributes", attributes, error);
+ secrets_object_delete(item);
+ }
+ else /* create a new item */
+ {
+ VERB2 log("creating event config : '%s'", event_name);
+ secrets_collection_create_text_item(collection, event_name, attributes, error);
+ }
+}
+
+static void save_event_config(const char *event_name,
+ GList *options,
+ bool store_passwords)
+{
+ bool dismissed = false;
+ GError *error = NULL;
+ struct secrets_object *collection = get_default_collection(&error);
+
+ if (error)
+ goto save_event_config_end;
+
+ if (!collection)
+ {
+ VERB2 log("going to create a new default collection '"SECRETS_COLLECTION_LABEL"'"
+ " with alias '"SECRETS_COLLECTION_ALIAS"'");
+
+ collection =
+ secrets_service_create_collection(SECRETS_COLLECTION_LABEL, SECRETS_COLLECTION_ALIAS,
+ &dismissed, &error);
+
+ if (error || dismissed)
+ goto save_event_config_end;
+ }
+
+ save_options(collection, event_name, options, store_passwords, &error);
+
+save_event_config_end:
+ if (dismissed)
+ secrets_api_set_unavailable();
+
+ if (error)
+ secrets_api_error(error, NULL);
+}
+
+/******************************************************************************/
+/* Public interface */
+/******************************************************************************/
+
+bool is_event_config_user_storage_available()
+{
+ return is_secrets_api_available();
+}
+
+/*
+ * Loads event config options for passed events
+ *
+ * @param event_config_list Events configs
+ */
+void load_event_config_data_from_user_storage(GHashTable *event_config_list)
+{
+ secrets_api_init();
+
+ if (is_secrets_api_available())
+ {
+ GError *error = NULL;
+ struct secrets_object *collection = get_default_collection(&error);
+
+ if (collection)
+ {
+ g_hash_table_foreach(event_config_list, &load_event_config, collection);
+ secrets_object_delete(collection);
+ }
+
+ if (error)
+ secrets_api_error(error, "D-Bus secrets API cannot provide default collection");
+ }
+ else
+ {
+ VERB1 log("cannot load user's configuration due to unavailability of D-Bus secrets API");
+ }
+}
+
+/*
+ * Saves an event_config options to some kind of session storage.
+ *
+ * @param event_name Lookup key
+ * @param event_config Event data
+ * @param store_passwords If TRUE stores options with passwords, otherwise skips them
+ */
+void save_event_config_data_to_user_storage(const char *event_name,
+ const event_config_t *event_config,
+ bool store_passwords)
+{
+ secrets_api_init();
+
+ if (is_secrets_api_available())
+ save_event_config(event_name, event_config->options, store_passwords);
+ else
+ {
+ VERB1 log("cannot save user's configuration due to unavailability of D-Bus secrets API");
+ }
+}
diff --git a/src/gui-wizard-gtk/main.c b/src/gui-wizard-gtk/main.c
index 05d01e9..e9632c3 100644
--- a/src/gui-wizard-gtk/main.c
+++ b/src/gui-wizard-gtk/main.c
@@ -140,7 +140,7 @@ int main(int argc, char **argv)
/* load /etc/abrt/events/foo.{conf,xml} stuff
and $XDG_CACHE_HOME/abrt/events/foo.conf */
load_event_config_data();
- load_event_config_data_from_keyring();
+ load_event_config_data_from_user_storage(g_event_config_list);
load_user_settings("report-gtk");
reload_problem_data_from_dump_dir();
--
1.7.7.6
11 years, 9 months
[PATCH] testsuite: improved stability and speed trac#633 trac#639 trac#644
by Jiri Moskovcak
- use preinstalled images instead of installing the system every time
- avoid problems with broken mirrors and Anaconda
- speeds the testing
- don't use cron job to run the tests
- causes SELinux problems
- use bridged networking instead of NAT
- makes it possible to ssh to the VM running the test
---
tests/helpers/bin/run | 106 ++++++++++++---------------------
tests/helpers/common/fun.sh | 19 ++++--
tests/helpers/targets/el6/defs.sh | 2 +
tests/helpers/targets/el6/runtests.sh | 35 +++++++++++
tests/helpers/targets/f16/defs.sh | 2 +
tests/helpers/targets/f16/runtests.sh | 35 +++++++++++
tests/helpers/targets/f17/defs.sh | 2 +
tests/helpers/targets/f17/runtests.sh | 35 +++++++++++
8 files changed, 163 insertions(+), 73 deletions(-)
create mode 100644 tests/helpers/targets/el6/runtests.sh
create mode 100644 tests/helpers/targets/f16/runtests.sh
create mode 100644 tests/helpers/targets/f17/runtests.sh
diff --git a/tests/helpers/bin/run b/tests/helpers/bin/run
index fe0815b..790fee3 100755
--- a/tests/helpers/bin/run
+++ b/tests/helpers/bin/run
@@ -3,6 +3,7 @@
source ~/common/globaldefs.sh
source ~/common/fun.sh
source ~/targets/${1}/defs.sh
+CURR_TARGET=$1
shift
PREPARE=
@@ -31,74 +32,46 @@ if [ ! -d data ]; then
fi
reinit_vm
-echo 'Getting kickstart'
-get_ks
-
-cp orig-ks.cfg custom-ks.cfg
-rm -f orig-ks.cfg
-
-echo 'Patching kickstart'
-
-cat ~/common/start_post_hunk >> custom-ks.cfg
-cat ~/common/git_hunk >> custom-ks.cfg
-
-# don't run tests automatically if --prepare is set
-test -z $PREPARE && cat ~/common/cron_hunk >> custom-ks.cfg
-
-# ssh key
-cat ~/common/ssh_pre_hunk >> custom-ks.cfg
-embed_file "/root/.ssh/id_rsa" ~/.ssh/id_rsa
-cat ~/common/ssh_post_hunk >> custom-ks.cfg
-
-# procmail cfg
-cat ~/common/procmail_hunk >> custom-ks.cfg
-
-# custom cfg
-embed_file "/root/abrt/tests/runtests/aux/config.sh.local" ./config.sh.local
-
-# fedorahosted alias
-embed_file "/etc/hosts" ~/common/hosts_hunk
-embed_file "/etc/motd" ~/common/motd_hunk
-
-add_rhel_repos
-add_abrt_repos
-
-# exclude build tests
-cat ~/common/exclude_build_tests >> custom-ks.cfg
-
-# disable gpg check
-cat ~/common/no_gpg_check >> custom-ks.cfg
-
-# %post
-cat ~/common/end_post_hunk >> custom-ks.cfg
-
-echo 'Running virt-install'
-virt-install --name $VM_NAME --ram "1300" \
- --connect qemu:///system \
- --location "$LOC" \
- --disk path=$DISK,cache=none \
- --initrd-inject=./custom-ks.cfg --extra-args "ks=file:/custom-ks.cfg ${INIT_EXTRA_ARGS}" \
- --noautoconsole \
- --os-type=linux \
- --os-variant=$OS_VARIANT \
- --graphics type=vnc \
- --quiet
-
-set +x
-echo 'virt-install done'
-echo -n "Zzzz (until VM is being installed): "
-while virsh --connect qemu:///system list | grep -q $VM_NAME; do
- echo -n '.'
- sleep 1m
-done
-echo 'x'
-
-sleep 30
virsh --connect qemu:///system start $VM_NAME
-cat /var/lib/libvirt/dnsmasq/default.leases
+if [ $? != 0 ]; then
+ # how about we create it here instead of dying??
+ echo "VM with name $VM_NAME does not exist!"
+ exit 1;
+fi
-test -z $PREPARE || exit 0
+echo "Wait a while for machine to start, before we start ping attact..."
+sleep 20;
+
+try=0;
+while true; do
+ ping -w 1 $IP &> /dev/null;
+ res=$?;
+ if [ $res == 0 ]; then
+ break;
+ fi;
+
+ if [ $try == 10 ]; then # max tries
+ echo "Seems like machine '$VM_NAME' doesn't want to talk with us on '$IP'"
+ exit 1;
+ fi
+ let try=try+1;
+ sleep 5; # wait between the attempts, otherwise it floods the log
+done;
+
+echo "Giving the sshd a while to start"
+sleep 10
+scp ~/targets/$CURR_TARGET/runtests.sh root@$IP:~
+if [ $? != 0 ]; then
+ echo "Can't upload runtests.sh to VM";
+ exit 1;
+fi;
+
+ssh root@$IP "sh ./runtests.sh"
+if [ $? != 0 ]; then
+ echo "Running the tests failed, bailing out..";
+ exit 1;
+fi;
echo -n "Zzzz (until VM is executing the tests): "
while virsh --connect qemu:///system list | grep -q $VM_NAME; do
@@ -107,9 +80,6 @@ while virsh --connect qemu:///system list | grep -q $VM_NAME; do
done
echo 'x'
-sleep 30
-set -x
-
handle_results "$DATA_DIR/data/" "/var/nightly_results/$( basename $DATA_DIR/)"
echo $result_path
test -d $result_path || exit 1
diff --git a/tests/helpers/common/fun.sh b/tests/helpers/common/fun.sh
index e948160..5517bf3 100644
--- a/tests/helpers/common/fun.sh
+++ b/tests/helpers/common/fun.sh
@@ -9,14 +9,23 @@ function reinit_vm() {
if virsh --connect qemu:///system list | grep -q $VM_NAME; then
echo 'Destroying virtual machine'
virsh --connect qemu:///system destroy $VM_NAME
- sleep 3
fi
- if virsh --connect qemu:///system list --all | grep -q $VM_NAME; then
- echo 'Undef virtual machine'
- virsh --connect qemu:///system undefine $VM_NAME
- sleep 1
+# if virsh --connect qemu:///system list --all | grep -q $VM_NAME; then
+# echo 'Undef virtual machine'
+# virsh --connect qemu:///system undefine $VM_NAME
+
+ echo "Restoring vm ${VM_NAME}"
+ # beware sudo!!
+ sudo dd if=/pub/VM/${VM_NAME}.img of=/dev/mapper/vg-${CURR_TARGET}_vm bs=4M
+ if [ $? -ne 0 ]; then
+ echo "Restoring VM failed";
+ exit 1;
+ else
+ echo "VM restored";
fi
+
+# fi
}
function get_ks() {
diff --git a/tests/helpers/targets/el6/defs.sh b/tests/helpers/targets/el6/defs.sh
index 57db622..5f001de 100644
--- a/tests/helpers/targets/el6/defs.sh
+++ b/tests/helpers/targets/el6/defs.sh
@@ -8,3 +8,5 @@ KS_NAME_PREFIX='brq_el6'
LOC='http://download.englab.brq.redhat.com/pub/rhel/rel-eng/latest-RHEL-6/6/Wo...'
DISK=$( echo /dev/mapper/*el6_vm )
REPOS_REQUIRED='el6_latest'
+MAC="52540010b4df"
+IP="10.34.25.207"
\ No newline at end of file
diff --git a/tests/helpers/targets/el6/runtests.sh b/tests/helpers/targets/el6/runtests.sh
new file mode 100644
index 0000000..3f365e6
--- /dev/null
+++ b/tests/helpers/targets/el6/runtests.sh
@@ -0,0 +1,35 @@
+#! /bin/bash
+
+pushd $PWD && {
+ cd /root && {
+ git clone git://abrt.brq.redhat.com/abrt.git ./abrt && {
+ cd ./abrt && {
+ case $(cut -d: -f4,5 /etc/system-release-cpe) in
+ enterprise_linux:6*)
+ git checkout rhel6
+ ;;
+ *)
+ ;;
+ esac
+ }
+ }
+ }
+ popd
+}
+
+cat > /root/abrt/tests/runtests/aux/config.sh.local << "_END_"
+export FORMAT_SCRIPT='aux/scp_format.sh'
+export REPORT_SCRIPT='aux/scp_report.sh'
+
+export SCPTO='virt_manage@abrt.brq.redhat.com:~/targets/el6/data/'
+
+export SHUTDOWN=1
+_END_
+
+
+EXCLUDE_TESTS="abrt-nightly-build|abrt-make-check|btparser-make-check|libreport-make-check"
+TEST_ORDER="/root/abrt/tests/runtests/aux/test_order"
+
+egrep -v "$EXCLUDE_TESTS" "$TEST_ORDER" > /tmp/test_order && mv /tmp/test_order "$TEST_ORDER"
+sed -i 's/OpenGPGCheck.*=.*yes/OpenGPGCheck = no/' /etc/abrt/abrt-action-save-package-data.conf
+screen -d -m /root/abrt/tests/runtests/run | tee -a /tmp/abrt-nightly-test.log
\ No newline at end of file
diff --git a/tests/helpers/targets/f16/defs.sh b/tests/helpers/targets/f16/defs.sh
index 42f44fd..95d4ffd 100644
--- a/tests/helpers/targets/f16/defs.sh
+++ b/tests/helpers/targets/f16/defs.sh
@@ -7,6 +7,8 @@ OS_VARIANT='fedora16'
KS_NAME_PREFIX='fedora_16'
LOC='http://download.englab.brq.redhat.com/pub/fedora/linux/releases/16/Fedora...'
DISK=$( echo /dev/mapper/*f16_vm )
+MAC="525400846b5b"
+IP="10.34.25.210"
# http://fedoraproject.org/wiki/Anaconda/Updates
INIT_EXTRA_ARGS="updates=http://abrt.brq.redhat.com/media/updates-anaconda.img"
diff --git a/tests/helpers/targets/f16/runtests.sh b/tests/helpers/targets/f16/runtests.sh
new file mode 100644
index 0000000..6929f4f
--- /dev/null
+++ b/tests/helpers/targets/f16/runtests.sh
@@ -0,0 +1,35 @@
+#! /bin/bash
+
+pushd $PWD && {
+ cd /root && {
+ git clone git://abrt.brq.redhat.com/abrt.git ./abrt && {
+ cd ./abrt && {
+ case $(cut -d: -f4,5 /etc/system-release-cpe) in
+ enterprise_linux:6*)
+ git checkout rhel6
+ ;;
+ *)
+ ;;
+ esac
+ }
+ }
+ }
+ popd
+}
+
+cat > /root/abrt/tests/runtests/aux/config.sh.local << "_END_"
+export FORMAT_SCRIPT='aux/scp_format.sh'
+export REPORT_SCRIPT='aux/scp_report.sh'
+
+export SCPTO='virt_manage@abrt.brq.redhat.com:~/targets/f16/data/'
+
+export SHUTDOWN=1
+_END_
+
+
+EXCLUDE_TESTS="abrt-nightly-build|abrt-make-check|btparser-make-check|libreport-make-check"
+TEST_ORDER="/root/abrt/tests/runtests/aux/test_order"
+
+egrep -v "$EXCLUDE_TESTS" "$TEST_ORDER" > /tmp/test_order && mv /tmp/test_order "$TEST_ORDER"
+
+screen -d -m /root/abrt/tests/runtests/run | tee -a /tmp/abrt-nightly-test.log
\ No newline at end of file
diff --git a/tests/helpers/targets/f17/defs.sh b/tests/helpers/targets/f17/defs.sh
index 7dcdd7c..57306c2 100644
--- a/tests/helpers/targets/f17/defs.sh
+++ b/tests/helpers/targets/f17/defs.sh
@@ -6,6 +6,8 @@ REPO='git://abrt.brq.redhat.com/abrt.git'
OS_VARIANT='fedora16'
KS_NAME_PREFIX='fedora_17'
LOC='http://download.englab.brq.redhat.com/pub/fedora/linux/releases/17/Fedora...'
+MAC="525400405da9"
+IP="10.34.25.200"
DISK=$( echo /dev/mapper/*f17_vm )
diff --git a/tests/helpers/targets/f17/runtests.sh b/tests/helpers/targets/f17/runtests.sh
new file mode 100644
index 0000000..4d43fde
--- /dev/null
+++ b/tests/helpers/targets/f17/runtests.sh
@@ -0,0 +1,35 @@
+#! /bin/bash
+
+pushd $PWD && {
+ cd /root && {
+ git clone git://abrt.brq.redhat.com/abrt.git ./abrt && {
+ cd ./abrt && {
+ case $(cut -d: -f4,5 /etc/system-release-cpe) in
+ enterprise_linux:6*)
+ git checkout rhel6
+ ;;
+ *)
+ ;;
+ esac
+ }
+ }
+ }
+ popd
+}
+
+cat > /root/abrt/tests/runtests/aux/config.sh.local << "_END_"
+export FORMAT_SCRIPT='aux/scp_format.sh'
+export REPORT_SCRIPT='aux/scp_report.sh'
+
+export SCPTO='virt_manage@abrt.brq.redhat.com:~/targets/f17/data/'
+
+export SHUTDOWN=1
+_END_
+
+
+EXCLUDE_TESTS="abrt-nightly-build|abrt-make-check|btparser-make-check|libreport-make-check"
+TEST_ORDER="/root/abrt/tests/runtests/aux/test_order"
+
+egrep -v "$EXCLUDE_TESTS" "$TEST_ORDER" > /tmp/test_order && mv /tmp/test_order "$TEST_ORDER"
+
+screen -d -m /root/abrt/tests/runtests/run | tee -a /tmp/abrt-nightly-test.log
\ No newline at end of file
--
1.7.10.4
11 years, 9 months
[PATCH 1/2] Merge create_dump_dir_from_problem_data() and save_dump_dir_from_problem_data()
by Denys Vlasenko
create_dump_dir_from_problem_data() adopts almost all new tricks from
save_dump_dir_from_problem_data(), but still returns struct dump_dir * -
the caller might want to use dd w/o the need to lock it again.
The libreport patch goes first. abrt one will follow.
--
vda
diff -x '*.po' -d -urpN libreport.8/src/include/problem_data.h libreport.9/src/include/problem_data.h
--- libreport.8/src/include/problem_data.h 2012-07-20 14:03:06.891337223 +0200
+++ libreport.9/src/include/problem_data.h 2012-07-23 18:48:46.990704360 +0200
@@ -98,8 +98,6 @@ problem_data_t *create_problem_data_for_
struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name);
-char* save_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name);
-
#ifdef __cplusplus
}
#endif
diff -x '*.po' -d -urpN libreport.8/src/lib/create_dump_dir.c libreport.9/src/lib/create_dump_dir.c
--- libreport.8/src/lib/create_dump_dir.c 2012-07-20 15:22:57.243932962 +0200
+++ libreport.9/src/lib/create_dump_dir.c 2012-07-23 18:48:40.480705400 +0200
@@ -31,16 +31,25 @@ static struct dump_dir *try_dd_create(co
struct dump_dir *create_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name)
{
- char dir_name[sizeof("abrt-tmp-"LIBREPORT_ISO_DATE_STRING_SAMPLE"-%lu") + sizeof(long)*3];
- snprintf(dir_name, sizeof(dir_name), "abrt-tmp-%s-%lu", iso_date_string(NULL), (long)getpid());
+ char *type = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER);
+
+ if (!type)
+ {
+ error_msg(_("Missing required item: '%s'"), FILENAME_ANALYZER);
+ return NULL;
+ }
+
+ char *problem_id = xasprintf("%s-%s-%lu"NEW_PD_SUFFIX, type, iso_date_string(NULL), (long)getpid());
+
+ VERB2 log("Saving to %s/%s", base_dir_name, problem_id);
struct dump_dir *dd;
if (base_dir_name)
- dd = try_dd_create(base_dir_name, dir_name);
+ dd = try_dd_create(base_dir_name, problem_id);
else
{
/* Try /var/run/abrt */
- dd = try_dd_create(LOCALSTATEDIR"/run/abrt", dir_name);
+ dd = try_dd_create(LOCALSTATEDIR"/run/abrt", problem_id);
/* Try $HOME/tmp */
if (!dd)
{
@@ -49,78 +58,18 @@ struct dump_dir *create_dump_dir_from_pr
{
home = concat_path_file(home, "tmp");
/*mkdir(home, 0777); - do we want this? */
- dd = try_dd_create(home, dir_name);
+ dd = try_dd_create(home, problem_id);
free(home);
}
}
//TODO: try user's home dir obtained by getpwuid(getuid())?
/* Try /tmp */
if (!dd)
- dd = try_dd_create("/tmp", dir_name);
- }
- if (!dd)
- return NULL;
-
- 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))
- {
- if (name[0] == '.' || strchr(name, '/'))
- {
- error_msg("Problem data field name contains disallowed chars: '%s'", name);
- goto next;
- }
-
-//FIXME: what to do with CD_FLAG_BINs??
- if (value->flags & CD_FLAG_BIN)
- goto next;
-
- dd_save_text(dd, name, value->content);
- next: ;
- }
-
- /* need to create basic files AFTER we save the pd to dump_dir
- * otherwise we can't skip already created files like in case when
- * reporting from anaconda where we can't read /etc/{system,redhat}-release
- * and os_release is taken from anaconda
- */
- dd_create_basic_files(dd, (uid_t)-1L, NULL);
-
- return dd;
-}
-
-char* save_dump_dir_from_problem_data(problem_data_t *problem_data, const char *base_dir_name)
-{
- char *type = problem_data_get_content_or_NULL(problem_data, FILENAME_ANALYZER);
-
- if (!type)
- {
- error_msg(_("Missing required item: '%s'"), FILENAME_ANALYZER);
- return NULL;
- }
-
- char *time_s = problem_data_get_content_or_NULL(problem_data, FILENAME_TIME);
- if (!time_s)
- {
- /* time is a required field, so if it's not provided add a default one */
- char buf[sizeof(unsigned long) * 3];
- time_t t = time(NULL);
- sprintf(buf, "%lu", (unsigned long)t);
- problem_data_add_text_noteditable(problem_data, FILENAME_TIME, buf);
+ dd = try_dd_create("/tmp", problem_id);
}
- char *problem_id = xasprintf("%s-%s-%lu"NEW_PD_SUFFIX, type, iso_date_string(NULL), (long)getpid());
-
- VERB2 log("Saving to %s/%s", base_dir_name, problem_id);
- struct dump_dir *dd = try_dd_create(base_dir_name, problem_id);
- if (!dd)
- {
- perror_msg("Can't create problem directory");
- free(problem_id);
- return NULL;
- }
+ if (!dd) /* try_dd_create() already emitted the error message */
+ goto ret;
GHashTableIter iter;
char *name;
@@ -152,19 +101,19 @@ char* save_dump_dir_from_problem_data(pr
dd_save_text(dd, name, value->content);
}
- problem_id[strlen(problem_id) - strlen(NEW_PD_SUFFIX)] = '\0';
+ /* need to create basic files AFTER we save the pd to dump_dir
+ * otherwise we can't skip already created files like in case when
+ * reporting from anaconda where we can't read /etc/{system,redhat}-release
+ * and os_release is taken from anaconda
+ */
+ dd_create_basic_files(dd, (uid_t)-1L, NULL);
+ problem_id[strlen(problem_id) - strlen(NEW_PD_SUFFIX)] = '\0';
char* new_path = concat_path_file(base_dir_name, problem_id);
-
VERB2 log("Renaming from '%s' to '%s'", dd->dd_dirname, new_path);
- if (dd_rename(dd, new_path) != 0)
- {
- free(problem_id);
- problem_id = NULL;
- }
-
- free(new_path);
- dd_close(dd);
+ dd_rename(dd, new_path);
- return problem_id;
+ ret:
+ free(problem_id);
+ return dd;
}
diff -x '*.po' -d -urpN libreport.8/src/lib/dump_dir.c libreport.9/src/lib/dump_dir.c
--- libreport.8/src/lib/dump_dir.c 2012-07-10 18:07:42.000000000 +0200
+++ libreport.9/src/lib/dump_dir.c 2012-07-20 15:29:41.245932431 +0200
@@ -463,9 +463,15 @@ void dd_create_basic_files(struct dump_d
{
char long_str[sizeof(long) * 3 + 2];
- time_t t = time(NULL);
- snprintf(long_str, sizeof(long_str), "%lu", (long)t);
- dd_save_text(dd, FILENAME_TIME, long_str);
+ char *time_str = dd_load_text_ext(dd, FILENAME_TIME,
+ DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
+ if (!time_str)
+ {
+ time_t t = time(NULL);
+ sprintf(long_str, "%lu", (long)t);
+ dd_save_text(dd, FILENAME_TIME, long_str);
+ }
+ free(time_str);
/* it doesn't make sense to create the uid file if uid == -1 */
if (uid != (uid_t)-1L)
@@ -484,7 +490,7 @@ void dd_create_basic_files(struct dump_d
* if it doesn't
* i.e: anaconda doesn't have /etc/{fedora,redhat}-release and trying to load it
* results in errors: rhbz#725857
- */
+ */
char *release = dd_load_text_ext(dd, FILENAME_OS_RELEASE,
DD_FAIL_QUIETLY_ENOENT | DD_LOAD_TEXT_RETURN_NULL_ON_FAILURE);
11 years, 9 months
[PATCH] a-h-e: open dump dir read only, write access usualy fails and isn't required
by Jakub Filak
Signed-off-by: Jakub Filak <jfilak(a)redhat.com>
---
src/daemon/abrt-handle-event.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/daemon/abrt-handle-event.c b/src/daemon/abrt-handle-event.c
index b372431..ef72f94 100644
--- a/src/daemon/abrt-handle-event.c
+++ b/src/daemon/abrt-handle-event.c
@@ -298,7 +298,7 @@ int main(int argc, char **argv)
break;
dump_dir_name[++i] = '\0';
- struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
+ struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ DD_OPEN_READONLY);
if (!dd)
return 1;
--
1.7.10.4
11 years, 9 months