Signed-off-by: Jiri Moskovcak jmoskovc@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
Signed-off-by: Jiri Moskovcak jmoskovc@redhat.com --- po/POTFILES.in | 1 + src/cli/Makefile.am | 1 + src/cli/abrt-cli.c | 1 + src/cli/builtin-cmd.h | 1 + src/cli/status.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+) create mode 100644 src/cli/status.c
diff --git a/po/POTFILES.in b/po/POTFILES.in index 250c1c5..9dd904e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -30,6 +30,7 @@ src/plugins/https-utils.c
src/cli/abrt-cli.c src/cli/list.c +src/cli/status.c src/plugins/analyze_VMcore.xml.in src/plugins/collect_GConf.xml.in src/plugins/collect_vimrc_system.xml.in diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index 1524312..4edf1c6 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -8,6 +8,7 @@ BUILTIN_C = BUILTIN_C += list.c BUILTIN_C += rm.c BUILTIN_C += report.c +BUILTIN_C += status.c
abrt_cli_SOURCES = $(CLI_C) $(BUILTIN_C) builtin-cmd.h abrt-cli-core.h
diff --git a/src/cli/abrt-cli.c b/src/cli/abrt-cli.c index 894ab25..ce4e396 100644 --- a/src/cli/abrt-cli.c +++ b/src/cli/abrt-cli.c @@ -147,6 +147,7 @@ int main(int argc, const char **argv) CMD(rm, _("Remove problem directory DIR")), CMD(report, _("Analyze and report problem data in DIR")), CMD(info, _("Print information about DIR")), + CMD(status, _("Print the count of the recent crashes")), {NULL, NULL, NULL} };
diff --git a/src/cli/builtin-cmd.h b/src/cli/builtin-cmd.h index cea77d8..491760b 100644 --- a/src/cli/builtin-cmd.h +++ b/src/cli/builtin-cmd.h @@ -24,5 +24,6 @@ extern int cmd_list(int argc, const char **argv); extern int cmd_rm(int argc, const char **argv); extern int cmd_report(int argc, const char **argv); extern int cmd_info(int argc, const char **argv); +extern int cmd_status(int argc, const char **argv);
#endif /* _BUILTIN-CMD_H_ */ diff --git a/src/cli/status.c b/src/cli/status.c new file mode 100644 index 0000000..6f228c6 --- /dev/null +++ b/src/cli/status.c @@ -0,0 +1,63 @@ +/* + Copyright (C) 2013 ABRT Team + Copyright (C) 2013 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 <unistd.h> +#include <sys/types.h> +#include "problem_api.h" + +int cmd_status(int argc, const char **argv) +{ + const char *program_usage_string = _( + "& status [DIR]..." + ); + + + bool opt_bare = false; + int opt_since = 0; + + struct options program_options[] = { + OPT__VERBOSE(&g_verbose), + OPT_GROUP(""), + OPT_BOOL ('b', "bare", &opt_bare, _("Print only the problem count without any message")), + OPT_INTEGER('s', "since", &opt_since, _("Print only the problems more recent than specified timestamp")), + OPT_END() + }; + + parse_opts(argc, (char **)argv, program_options, program_usage_string); + argv += optind; + + GList *problem_dir_list = NULL; + while (*argv) + problem_dir_list = g_list_append(problem_dir_list, xstrdup(*argv++)); + + unsigned int problem_count = get_problems_count(problem_dir_list, opt_since); + + /* show only if there is at least 1 problem or user set the -v */ + if (problem_count > 0 || g_verbose > 0) + { + if (opt_bare) + printf("%u", problem_count); + else + printf(_("ABRT has detected '%u' problem(s). (For more info run: $ abrt-cli list --full)\n"), problem_count); + } + + list_free_with_free(problem_dir_list); + + return 0; +}
- this script notifies users about existing when he logs in to the machine - it remembers the last time when it was executed and shows only the number of new crashes since the last run - uses $HOME/.cache/abrt even though the XDG dirs are not default in RHEL6, but it doesn't make sense to make it differ from Fedora
Signed-off-by: Jakub Filak jfilak@redhat.com Signed-off-by: Jiri Moskovcak jmoskovc@redhat.com --- src/cli/Makefile.am | 4 ++++ src/cli/abrt-console-notification.sh | 22 ++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100755 src/cli/abrt-console-notification.sh
diff --git a/src/cli/Makefile.am b/src/cli/Makefile.am index 4edf1c6..3e4c976 100644 --- a/src/cli/Makefile.am +++ b/src/cli/Makefile.am @@ -22,4 +22,8 @@ abrt_cli_LDADD = \ $(LIBREPORT_LIBS) \ ../lib/libabrt.la
+profileconfigdir = $(sysconfdir)/profile.d +dist_profileconfig_DATA = \ + abrt-console-notification.sh + DEFS = -DLOCALEDIR="$(localedir)" @DEFS@ diff --git a/src/cli/abrt-console-notification.sh b/src/cli/abrt-console-notification.sh new file mode 100755 index 0000000..4082909 --- /dev/null +++ b/src/cli/abrt-console-notification.sh @@ -0,0 +1,22 @@ +LPATHDIR="$HOME/.cache/abrt" +SINCEFILE="$LPATHDIR/lastnotification" + +if [ ! -f "$LPATHDIR" ]; then + mkdir -p "$LPATHDIR" +fi + +TMPPATH=`mktemp --tmpdir="$LPATHDIR" lastnotification.XXXXXXXX 2> /dev/null` + +SINCE=0 +if [ -f "$SINCEFILE" ]; then + SINCE=`cat $SINCEFILE 2> /dev/null` +fi + +# always update the lastnotification +if [ -f "$TMPPATH" ]; then + date +%s > "$TMPPATH" + mv "$TMPPATH" "$SINCEFILE" +fi + +abrt-cli status --since="$SINCE" 2> /dev/null +
Signed-off-by: Jiri Moskovcak jmoskovc@redhat.com --- abrt.spec.in | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/abrt.spec.in b/abrt.spec.in index c182db2..50be01b 100644 --- a/abrt.spec.in +++ b/abrt.spec.in @@ -186,6 +186,16 @@ Provides: bug-buddy %description desktop Virtual package to make easy default installation on desktop environments.
+%package console-notification +Summary: ABRT console notification script +Group: Applications/System +Requires: %{name} = %{version}-%{release} +Requires: %{name}-cli = %{version}-%{release} + +%description console-notification +A small script which prints a count of detected problems when someone logs in +to the shell + %prep %setup -q
@@ -534,6 +544,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %files desktop %defattr(-,root,root,-)
+%files console-notification +%config(noreplace) %{_sysconfdir}/profile.d/abrt-console-notification.sh + %changelog * Wed Mar 16 2011 Jiri Moskovcak jmoskovc@redhat.com 2.0.0-1 - update to the latest upstream version
Works fine. Pushed. Thanks!
----- Original Message ----- From: "Jiri Moskovcak" jmoskovc@redhat.com To: crash-catcher@lists.fedorahosted.org Sent: Friday, May 10, 2013 12:43:55 PM Subject: [ABRT EL6 PATCH 4/4] spec: added the console-notification - rhbz#961231
Signed-off-by: Jiri Moskovcak jmoskovc@redhat.com --- abrt.spec.in | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/abrt.spec.in b/abrt.spec.in index c182db2..50be01b 100644 --- a/abrt.spec.in +++ b/abrt.spec.in @@ -186,6 +186,16 @@ Provides: bug-buddy %description desktop Virtual package to make easy default installation on desktop environments.
+%package console-notification +Summary: ABRT console notification script +Group: Applications/System +Requires: %{name} = %{version}-%{release} +Requires: %{name}-cli = %{version}-%{release} + +%description console-notification +A small script which prints a count of detected problems when someone logs in +to the shell + %prep %setup -q
@@ -534,6 +544,9 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : %files desktop %defattr(-,root,root,-)
+%files console-notification +%config(noreplace) %{_sysconfdir}/profile.d/abrt-console-notification.sh + %changelog * Wed Mar 16 2011 Jiri Moskovcak jmoskovc@redhat.com 2.0.0-1 - update to the latest upstream version
crash-catcher@lists.fedorahosted.org