- so they can be used in abrt-cli and gui
Signed-off-by: Jiri Moskovcak <jmoskovc(a)redhat.com>
---
po/POTFILES.in | 1 +
src/dbus/abrt-dbus.c | 192 +++----------------------------------
src/include/Makefile.am | 3 +-
src/include/problem_api.h | 55 +++++++++++
src/lib/Makefile.am | 1 +
src/lib/problem_api.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 311 insertions(+), 181 deletions(-)
create mode 100644 src/include/problem_api.h
create mode 100644 src/lib/problem_api.c
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 05fba74..9054e3f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,7 @@ src/daemon/abrt-handle-event.c
src/lib/abrt_conf.c
src/lib/hooklib.c
src/lib/problem_api.c
+src/lib/problem_api_dbus.c
src/lib/ignored_problems.c
src/plugins/abrt-action-analyze-backtrace.c
src/plugins/abrt-action-analyze-c.c
diff --git a/src/dbus/abrt-dbus.c b/src/dbus/abrt-dbus.c
index 9d7f1ff..0766aa0 100644
--- a/src/dbus/abrt-dbus.c
+++ b/src/dbus/abrt-dbus.c
@@ -7,6 +7,7 @@
#include "abrt-polkit.h"
#include "abrt-dbus.h"
#include <libreport/dump_dir.h>
+#include "problem_api.h"
static GMainLoop *loop;
static guint g_timeout_source;
@@ -128,183 +129,6 @@ static uid_t get_caller_uid(GDBusConnection *connection,
GDBusMethodInvocation *
return caller_uid;
}
-/*
- * Structure for simple conditions based on problem fields
- */
-struct problem_condition
-{
- /* a name of filed required by evaluate function */
- const char *field_name;
- /* extra data passed to evaluate function */
- const void *args;
- /* evaluate function returning TRUE if condition was passed */
- bool (*evaluate)(const char *, const void *);
-};
-
-/*
- * Evaluates a NULL-terminated list of problem conditions as a logical conjunction
- */
-static bool problem_condition_evaluate_and(struct dump_dir *dd,
- const struct problem_condition *const
*condition)
-{
- /* We stop on the first FALSE condition */
- while (condition && *condition != NULL)
- {
- const struct problem_condition *c = *condition;
- char *field_data = dd_load_text(dd, c->field_name);
- bool value = c->evaluate(field_data, c->args);
- free(field_data);
- if (!value)
- return false;
- ++condition;
- }
-
- return true;
-}
-
-/*
- * Goes through all problems and selects only problems accessible by caller_uid and
- * problems for which an and_filter gets TRUE
- *
- * @param condition a NULL-terminated list of problem conditions evaluated
- * as conjunction, can be NULL (means always TRUE)
- */
-static GList* scan_directory(const char *path,
- uid_t caller_uid,
- const struct problem_condition *const *condition)
-{
- GList *list = NULL;
-
- DIR *dp = opendir(path);
- if (!dp)
- {
- /* We don't want to yell if, say, $XDG_CACHE_DIR/abrt/spool doesn't exist
*/
- //perror_msg("Can't open directory '%s'", path);
- return list;
- }
-
- struct dirent *dent;
- while ((dent = readdir(dp)) != NULL)
- {
- if (dot_or_dotdot(dent->d_name))
- continue; /* skip "." and ".." */
-
- char *full_name = concat_path_file(path, dent->d_name);
- if (dump_dir_accessible_by_uid(full_name, caller_uid))
- {
- /* Silently ignore *any* errors, not only EACCES.
- * We saw "lock file is locked by process PID" error
- * when we raced with wizard.
- */
- int sv_logmode = logmode;
- logmode = 0;
- struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY |
DD_FAIL_QUIETLY_EACCES);
- logmode = sv_logmode;
- /* or we could just setuid?
- - but it would require locking, because we want to setuid back before we
server another request..
- */
- if (dd)
- {
- if (problem_condition_evaluate_and(dd, condition))
- {
- list = g_list_prepend(list, full_name);
- full_name = NULL;
- }
- dd_close(dd); //doesn't fail even if dd == NULL
- }
- }
- free(full_name);
- }
- closedir(dp);
-
- /* Why reverse?
- * Because N*prepend+reverse is faster than N*append
- */
- return g_list_reverse(list);
-}
-
-/* Self explaining time interval structure */
-struct time_interval
-{
- unsigned long from;
- unsigned long to;
-};
-
-/*
- * A problem condition evaluate function for checking of the TIME field against
- * an allowed interval
- *
- * @param field_data a content from the PID field
- * @param args a pointer to an instance of struct time_interval
- * @return TRUE if a field value is in a specified interval; otherwise FALSE
- */
-static bool time_interval_problem_condition(const char *field_data, const void *args)
-{
- const struct time_interval *const interval = (const struct time_interval *)args;
- const time_t timestamp = atol(field_data);
-
- return interval->from <= timestamp && timestamp <= interval->to;
-}
-
-/*
- * A problem condition evaluate function passed if strings are equal
- *
- * @param field_data a content of a field
- * @param args a checked string
- * @return TRUE if both strings are equal; otherwise FALSE
- */
-static bool equal_string_problem_condition(const char *field_data, const void *args)
-{
- return !strcmp(field_data, (const char *)args);
-}
-
-static GVariant *get_problem_dirs_for_uid(uid_t uid, const char *dump_location)
-{
- GList *dirs = scan_directory(dump_location, uid, NULL);
- GVariant *result = variant_from_string_list(dirs);
- list_free_with_free(dirs);
- return result;
-}
-
-/*
- * Finds problems with the specified element and which were created in the interval
- */
-static GVariant *get_problem_dirs_for_element_in_time(uid_t uid,
- const char *element,
- const char *value,
- unsigned long timestamp_from,
- unsigned long timestamp_to,
- const char *dump_location)
-{
- const struct problem_condition elementc = {
- .field_name = element,
- .args = value,
- .evaluate = equal_string_problem_condition,
- };
-
- const struct time_interval interval = {
- .from = timestamp_from,
- .to = timestamp_to
- };
-
- const struct problem_condition timec = {
- .field_name = FILENAME_TIME,
- .args = &interval,
- .evaluate = time_interval_problem_condition
- };
-
- const struct problem_condition *const condition[] = {
- &elementc,
- &timec,
- NULL
- };
-
- GList *dirs = scan_directory(dump_location, uid, condition);
- GVariant *result = variant_from_string_list(dirs);
- list_free_with_free(dirs);
- return result;
-}
-
static bool allowed_problem_dir(const char *dir_name)
{
//HACK HACK HACK! Disabled for now until we fix clients (abrt-gui) to not pass
/home/user/.cache/abrt/spool
@@ -477,7 +301,9 @@ static void handle_method_call(GDBusConnection *connection,
if (g_strcmp0(method_name, "GetProblems") == 0)
{
- response = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
+ GList *dirs = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
+ response = variant_from_string_list(dirs);
+ list_free_with_free(dirs);
g_dbus_method_invocation_return_value(invocation, response);
//I was told that g_dbus_method frees the response
@@ -498,7 +324,10 @@ static void handle_method_call(GDBusConnection *connection,
caller_uid = 0;
}
- response = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
+ GList * dirs = get_problem_dirs_for_uid(caller_uid, g_settings_dump_location);
+ response = variant_from_string_list(dirs);
+
+ list_free_with_free(dirs);
g_dbus_method_invocation_return_value(invocation, response);
return;
@@ -788,9 +617,12 @@ static void handle_method_call(GDBusConnection *connection,
if (all && polkit_check_authorization_dname(caller,
"org.freedesktop.problems.getall") == PolkitYes)
caller_uid = 0;
- response = get_problem_dirs_for_element_in_time(caller_uid, element, value,
timestamp_from,
+ GList *dirs = get_problem_dirs_for_element_in_time(caller_uid, element, value,
timestamp_from,
timestamp_to,
g_settings_dump_location);
+ response = variant_from_string_list(dirs);
+
+ list_free_with_free(dirs);
g_dbus_method_invocation_return_value(invocation, response);
return;
}
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index ed63afd..addbaa5 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -5,4 +5,5 @@ libabrt_include_HEADERS = \
libabrt.h \
abrt-dbus.h \
hooklib.h \
- satyr-compat.h
+ satyr-compat.h \
+ problem_api.h
diff --git a/src/include/problem_api.h b/src/include/problem_api.h
new file mode 100644
index 0000000..3b1dfd3
--- /dev/null
+++ b/src/include/problem_api.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) ABRT Team
+ Copyright (C) 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 <glib.h>
+#include <libabrt.h>
+
+/*
+ * Structure for simple conditions based on problem fields
+ */
+struct problem_condition
+{
+ /* a name of filed required by evaluate function */
+ const char *field_name;
+ /* extra data passed to evaluate function */
+ const void *args;
+ /* evaluate function returning TRUE if condition was passed */
+ bool (*evaluate)(const char *, const void *);
+};
+
+/* Retrieves the list of directories currently used as a problem storage
+ * The result must be freed by caller
+ * @returns List of strings representing the full path to dirs
+*/
+GList *get_problem_storages();
+GList *get_problem_dirs_for_uid(uid_t uid, const char *dump_location);
+GList *get_problem_dirs_for_element_in_time(uid_t uid,
+ const char *element,
+ const char *value,
+ unsigned long timestamp_from,
+ unsigned long timestamp_to,
+ const char *dump_location);
+
+/* Counts all problems in given directories
+ *
+ * @paths[in] list of paths to scan (pass NULL to use the default problem directories)
+ * @since[in]
+ * @returns count of problems
+ */
+unsigned int get_problems_count(GList *paths, unsigned long since);
\ No newline at end of file
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 281e5f3..d5c4f5f 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -12,6 +12,7 @@ libabrt_la_SOURCES = \
abrt_glib.c \
migrate_dirs.c \
check_recent_crash_file.c \
+ problem_api.c \
problem_api_dbus.c \
ignored_problems.c
diff --git a/src/lib/problem_api.c b/src/lib/problem_api.c
new file mode 100644
index 0000000..b7dad47
--- /dev/null
+++ b/src/lib/problem_api.c
@@ -0,0 +1,240 @@
+/*
+ Copyright (C) ABRT Team
+ Copyright (C) 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 <glib.h>
+#include <sys/time.h>
+#include "problem_api.h"
+
+/*
+ * Evaluates a NULL-terminated list of problem conditions as a logical conjunction
+ */
+static bool problem_condition_evaluate_and(struct dump_dir *dd,
+ const struct problem_condition *const
*condition)
+{
+ /* We stop on the first FALSE condition */
+ while (condition && *condition != NULL)
+ {
+ const struct problem_condition *c = *condition;
+ char *field_data = dd_load_text(dd, c->field_name);
+ bool value = c->evaluate(field_data, c->args);
+ free(field_data);
+ if (!value)
+ return false;
+ ++condition;
+ }
+
+ return true;
+}
+
+/*
+ * Goes through all problems and selects only problems accessible by caller_uid and
+ * problems for which an and_filter gets TRUE
+ *
+ * @param condition a NULL-terminated list of problem conditions evaluated
+ * as conjunction, can be NULL (means always TRUE)
+ */
+static GList* scan_directory(const char *path,
+ uid_t caller_uid,
+ const struct problem_condition *const *condition)
+{
+ GList *list = NULL;
+
+ DIR *dp = opendir(path);
+ if (!dp)
+ {
+ /* We don't want to yell if, say, $XDG_CACHE_DIR/abrt/spool doesn't exist
*/
+ //perror_msg("Can't open directory '%s'", path);
+ return list;
+ }
+
+ struct dirent *dent;
+ while ((dent = readdir(dp)) != NULL)
+ {
+ if (dot_or_dotdot(dent->d_name))
+ continue; /* skip "." and ".." */
+
+ char *full_name = concat_path_file(path, dent->d_name);
+ if (dump_dir_accessible_by_uid(full_name, caller_uid))
+ {
+ /* Silently ignore *any* errors, not only EACCES.
+ * We saw "lock file is locked by process PID" error
+ * when we raced with wizard.
+ */
+ int sv_logmode = logmode;
+ logmode = 0;
+ struct dump_dir *dd = dd_opendir(full_name, DD_OPEN_READONLY |
DD_FAIL_QUIETLY_EACCES | DD_DONT_WAIT_FOR_LOCK);
+ logmode = sv_logmode;
+ /* or we could just setuid?
+ - but it would require locking, because we want to setuid back before we
server another request..
+ */
+ if (dd)
+ {
+ if (!condition || problem_condition_evaluate_and(dd, condition))
+ {
+ list = g_list_prepend(list, full_name);
+ full_name = NULL;
+ }
+ dd_close(dd); //doesn't fail even if dd == NULL
+ }
+ }
+ free(full_name);
+ }
+ closedir(dp);
+
+ /* Why reverse?
+ * Because N*prepend+reverse is faster than N*append
+ */
+ return g_list_reverse(list);
+}
+
+/* Self explaining time interval structure */
+struct time_interval
+{
+ unsigned long from;
+ unsigned long to;
+};
+
+/*
+ * A problem condition evaluate function for checking of the TIME field against
+ * an allowed interval
+ *
+ * @param field_data a content from the PID field
+ * @param args a pointer to an instance of struct time_interval
+ * @return TRUE if a field value is in a specified interval; otherwise FALSE
+ */
+static bool time_interval_problem_condition(const char *field_data, const void *args)
+{
+ const struct time_interval *const interval = (const struct time_interval *)args;
+ const time_t timestamp = atol(field_data);
+
+ return interval->from <= timestamp && timestamp <= interval->to;
+}
+
+/*
+ * A problem condition evaluate function passed if strings are equal
+ *
+ * @param field_data a content of a field
+ * @param args a checked string
+ * @return TRUE if both strings are equal; otherwise FALSE
+ */
+static bool equal_string_problem_condition(const char *field_data, const void *args)
+{
+ return !strcmp(field_data, (const char *)args);
+}
+
+GList *get_problem_dirs_for_uid(uid_t uid, const char *dump_location)
+{
+ GList *dirs = scan_directory(dump_location, uid, NULL);
+ return dirs;
+}
+
+/*
+ * Finds problems which were created in the interval
+ */
+GList *get_problem_dirs_for_element_in_time(uid_t uid,
+ const char *element,
+ const char *value,
+ unsigned long timestamp_from,
+ unsigned long timestamp_to,
+ const char *dump_location)
+{
+ struct timeval tv;
+ /* use the current time if timestamp_to is 0 */
+ if (timestamp_to == 0) {
+ gettimeofday(&tv, NULL);
+ timestamp_to = tv.tv_sec;
+ }
+
+
+ const struct problem_condition elementc = {
+ .field_name = element,
+ .args = value,
+ .evaluate = equal_string_problem_condition,
+ };
+
+ const struct time_interval interval = {
+ .from = timestamp_from,
+ .to = timestamp_to,
+ };
+
+ const struct problem_condition timec = {
+ .field_name = FILENAME_TIME,
+ .args = &interval,
+ .evaluate = time_interval_problem_condition
+ };
+
+ const struct problem_condition *const condition[] = {
+ &timec,
+ element ? &elementc : NULL,
+ NULL
+ };
+ GList *dirs = scan_directory(dump_location, uid, condition);
+ return dirs;
+}
+
+GList *get_problem_storages()
+{
+ GList *pths = NULL;
+ load_abrt_conf();
+ pths = g_list_append(pths, xstrdup(g_settings_dump_location));
+ //no needed, we don't steal directories anymore
+ pths = g_list_append(pths, concat_path_file(g_get_user_cache_dir(),
"abrt/spool"));
+ free_abrt_conf_data();
+
+ return pths;
+}
+
+
+typedef struct problem_count_info {
+ int problem_count;
+ unsigned long since;
+ unsigned long until;
+
+} problem_count_info_t;
+
+static void count_problems_in_dir(char *path, gpointer problem_counter)
+{
+ problem_count_info_t *pci = (problem_count_info_t *)problem_counter;
+ VERB2 log("scanning '%s' for problems since %lu", path,
pci->since);
+ GList *problems = get_problem_dirs_for_element_in_time(getuid(), NULL /*don't
filter by element*/, NULL, pci->since, pci->until, path);
+ pci->problem_count += g_list_length(problems);
+ list_free_with_free(problems);
+}
+
+unsigned int get_problems_count(GList *paths, unsigned long since)
+{
+ GList *pths = NULL;
+
+ if (paths == NULL)
+ {
+ pths = get_problem_storages();
+ }
+
+ problem_count_info_t pci;
+
+ pci.problem_count = 0;
+ pci.since = since;
+ pci.until = 0;
+
+ g_list_foreach(paths ? paths : pths, (GFunc)count_problems_in_dir, &pci);
+
+ list_free_with_free(pths);
+
+ return pci.problem_count;
+}
\ No newline at end of file
--
1.8.1.4