/*
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 <paths.h>
#include "libabrt.h"
#define XORG_CONF "xorg.conf"
static
void trim_spaces(char *str)
{
char *src = str;
char *dst = str;
while (*src)
{
if (!isspace(*src))
*dst++ = *src;
src++;
}
*dst = '\0';
}
static
char* is_in_comma_separated_list_with_fmt(const char *value, const char *fmt, const char *list)
{
if (!list)
return false;
while (*list)
{
const char *comma = strchrnul(list, ',');
char *pattern = xasprintf(fmt, (int)(comma - list), list);
char *match = strstr(value, pattern);
free(pattern);
if (match)
return xstrndup(list, comma - list);
if (!*comma)
break;
list = comma + 1;
}
return NULL;
}
int main(int argc, char **argv)
{
/* I18n */
setlocale(LC_ALL, "");
#if ENABLE_NLS
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
#endif
abrt_init(argv);
const char *dump_dir_name = ".";
/* Can't keep these strings/structs static: _() doesn't support that */
const char *program_usage_string = _(
"& [-v] -d DIR\n"
"\n"
"Calculates and saves UUID and DUPHASH for xorg problem directory DIR"
);
enum {
OPT_v = 1 << 0,
OPT_d = 1 << 1,
};
/* Keep enum above and order of options below in sync! */
struct options program_options[] = {
OPT__VERBOSE(&g_verbose),
OPT_STRING('d', NULL, &dump_dir_name, "DIR", _("Problem directory")),
OPT_END()
};
/*unsigned opts =*/ parse_opts(argc, argv, program_options, program_usage_string);
export_abrt_envvars(0);
map_string_t *settings = new_map_string();
log_notice("Loading settings from '%s'", XORG_CONF);
load_abrt_plugin_conf_file(XORG_CONF, settings);
log_debug("Loaded '%s'", XORG_CONF);
char *BlacklistedXorgModules = xstrdup(get_map_string_item_or_empty(settings, "BlacklistedXorgModules"));
trim_spaces(BlacklistedXorgModules);
free_map_string(settings);
struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0);
if (!dd)
return 1;
char *backtrace = dd_load_text(dd, FILENAME_BACKTRACE);
char *xorg_log = dd_load_text_ext(dd, "Xorg.0.log", DD_FAIL_QUIETLY_ENOENT);
char *blacklisted = is_in_comma_separated_list_with_fmt(backtrace, "/%.*s", BlacklistedXorgModules);
if (!blacklisted)
blacklisted = is_in_comma_separated_list_with_fmt(xorg_log, "LoadModule: \"%.*s\"", BlacklistedXorgModules);
/* get and save crash_function */
/* xorg backtrace is extracted from journal and looks like:
* 0: /usr/libexec/Xorg (OsLookupColor+0x139) [0x59ab89]
* 1: /lib64/libc.so.6 (__restore_rt+0x0) [0x7f2b13545b1f]
* 2: /lib64/libc.so.6 (__select_nocancel+0xa) [0x7f2b13609e7a]
* 3: /usr/libexec/Xorg (WaitForSomething+0x1c8) [0x593568]
* 4: /usr/libexec/Xorg (SendErrorToClient+0x111) [0x43a3a1]
*/
char *crash_function = strchr(backtrace, '(');
if (crash_function++)
{
char *end = strchr(crash_function, '+');
if (end)
*end = '\0';
else
{
end = strchr(crash_function, ')');
*end = '\0';
}
dd_save_text(dd, FILENAME_CRASH_FUNCTION, crash_function);
}
free(backtrace);
free(xorg_log);
if (blacklisted)
{
char *foobared = xasprintf(_("Module '%s' was loaded - won't report this crash"), blacklisted);
free(blacklisted);
dd_save_text(dd, FILENAME_NOT_REPORTABLE, foobared);
free(foobared);
dd_close(dd);
return 0;
}
dd_close(dd);
xchdir(dump_dir_name);
/* Get ready for extremely ugly sight.
*
* # Generate duplicate detection hashes.
* # To err on the "flag it as a dup" side is way better than the opposite.
* # To this end:
* # - sanitize whitespace
* # - remove N: prefix
* # - remove path: we don't care whether it's /usr/lib64/foo or /lib/foo
* # - remove VERSION from so.VERSION
* # - drop main() invocation
* # - replace all hex constants with string "0xZ".
* # - drop adjacent duplicate lines
*/
execlp(_PATH_BSHELL, _PATH_BSHELL, "-c",
"sed \\"
"\n"" -e 's/[ \\t][ \\t]*/ /g' -e 's/ *$//' \\"
"\n"" -e 's/^[0-9][0-9]*: //' \\"
"\n"" -e 's@^/[^ ]*/@@' \\"
"\n"" -e 's/\\.so\\.[0-9][0-9]*/.so/' \\"
"\n"" -e '/libc_start_main/d' \\"
"\n"" -e 's/0x[0-9a-fA-F][0-9a-fA-F]*/0xZ/g' \\"
"\n"" backtrace \\"
"\n""| uniq \\"
"\n""| sha1sum | sed 's/[ \\t].*//' >uuid"
"\n""test -f uuid && cp uuid duphash",
NULL);
perror_msg_and_die("Can't execute '%s'", _PATH_BSHELL);
}