[ABRT EL6 PATCH 1/4] created problem_api - part of rhbz#961231

Jiri Moskovcak jmoskovc at redhat.com
Fri May 10 10:43:52 UTC 2013


Signed-off-by: Jiri Moskovcak <jmoskovc at redhat.com>
---
 po/POTFILES.in            |   2 +
 src/include/Makefile.am   |   3 +-
 src/include/problem_api.h |  55 +++++++++++
 src/lib/Makefile.am       |   3 +-
 src/lib/problem_api.c     | 240 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 301 insertions(+), 2 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 9cc76a1..250c1c5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -11,6 +11,8 @@ src/daemon/abrt-handle-event.c
 src/gui-gtk/abrt.desktop.in
 src/gui-gtk/main.c
 src/lib/abrt_conf.c
+src/lib/hooklib.c
+src/lib/problem_api.c
 src/plugins/abrt-action-analyze-backtrace.c
 src/plugins/abrt-action-analyze-c.c
 src/plugins/abrt-action-analyze-oops.c
diff --git a/src/include/Makefile.am b/src/include/Makefile.am
index c3317d7..6b25ce4 100644
--- a/src/include/Makefile.am
+++ b/src/include/Makefile.am
@@ -2,4 +2,5 @@ libabrt_includedir = \
     $(includedir)/abrt
 
 libabrt_include_HEADERS = \
-    libabrt.h
+    libabrt.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 afc106c..5ecb593 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -9,7 +9,8 @@ libabrt_la_SOURCES = \
     hooklib.c \
     daemon_is_ok.c \
     kernel.c \
-    check_recent_crash_file.c
+    check_recent_crash_file.c \
+    problem_api.c
 
 libabrt_la_CPPFLAGS = \
     -Wall -Wwrite-strings -Werror \
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



More information about the Crash-catcher mailing list