From 72fcbace66a681babd08dd00895d7c8cf27984d5 Mon Sep 17 00:00:00 2001 From: William Douglas Date: Wed, 4 May 2011 13:12:45 -0700 Subject: [PATCH] add meaningful package list details for files in coredump Signed-off-by: William Douglas --- Makefile | 2 +- coredump.c | 339 ++++++++++++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 269 insertions(+), 72 deletions(-) diff --git a/Makefile b/Makefile index e25283d..62c78b9 100644 --- a/Makefile +++ b/Makefile @@ -12,7 +12,7 @@ CC ?= gcc CFLAGS := -O2 -g -fstack-protector -D_FORTIFY_SOURCE=2 -Wall -W -Wstrict-prototypes -Wundef -fno-common -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wformat -Wformat-security -Werror=format-security -MY_CFLAGS := `pkg-config --cflags libnotify gtk+-2.0 libproxy-1.0` +MY_CFLAGS := `pkg-config --cflags libnotify gtk+-2.0 libproxy-1.0 glib-2.0` # # pkg-config tends to make programs pull in a ton of libraries, not all # are needed. -Wl,--as-needed tells the linker to just drop unused ones, diff --git a/coredump.c b/coredump.c index b281204..7b74ee3 100644 --- a/coredump.c +++ b/coredump.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "corewatcher.h" @@ -43,9 +44,6 @@ int do_unlink = 0; int uid; int sig; -char *package; -char *component; -char *arch; #define MAX(A,B) ((A) > (B) ? (A) : (B)) @@ -159,61 +157,254 @@ void set_wrapped_app(char *line) */ } -void get_package_info(char *appfile) { - char *command = NULL, *line = NULL; +GList *get_core_file_list(char *appfile, char *dump_text) +{ + char *txt = NULL, *part = NULL; + char delim[] = " ',`;\n\""; + char *c; + GList *files = NULL; + + if (!(txt = strdup(dump_text))) + return NULL; + + part = strtok(txt, delim); + while(part) { + if (strstr(part, "/")) { + if (!(c = strdup(part))) + continue; + files = g_list_prepend(files, c); + } + part = strtok(NULL, delim); + } + if ((c = strdup(appfile))) + files = g_list_prepend(files, c); + + return files; +} + +char *run_cmd(char *cmd) +{ + char *line = NULL, *str = NULL; char *c; FILE *file; int ret = 0; size_t size = 0; - if (asprintf(&command, "rpm -q --whatprovides %s --queryformat \"%%{NAME}-%%{VERSION}-%%{RELEASE}-%%{ARCH}\"", appfile) < 0) { - package = strdup("Unknown"); - } else { - file = popen(command, "r"); - free(command); - ret = getline(&line, &size, file); - if ((!size) || (ret < 0)) { - package = strdup("Unknown"); - } else { - c = strchr(line, '\n'); - if (c) *c = 0; - package = strdup(line); - } - pclose(file); + file = popen(cmd, "r"); + ret = getline(&line, &size, file); + if (size || ret >= 0) { + c = strchr(line, '\n'); + if (c) *c = 0; + str = strdup(line); } + free(line); + pclose(file); - if (asprintf(&command, "rpm -q --whatprovides %s --queryformat \"%%{NAME}\"", appfile) < 0) { - component = strdup("Unknown"); - } else { - file = popen(command, "r"); - free(command); - ret = getline(&line, &size, file); - if ((!size) || (ret < 0)) { - component = strdup("Unknown"); - } else { - c = strchr(line, '\n'); - if (c) *c = 0; - component = strdup(line); + return str; +} + +char *lookup_part(char *check, char *line) +{ + char *c1, *c2; + char *c = NULL; + if (strncmp(check, line, strlen(check))) + return NULL; + if (!(c1 = strstr(line, ":"))) + return NULL; + c1 += 2; + if (!(c2 = strstr(c1, " "))) + return NULL; + *c2 = 0; + if (!(c = strdup(c1))) + return NULL; + return c; +} + +int append(char **s, char *e, char *o) +{ + char *t; + if (!s || !(*s)) + return -1; + t = *s; + *s = NULL; + if (asprintf(s, "%s%s%s", t, o, e) < 0) { + *s = t; + return -1; + } + free(t); + return 0; +} + +void build_times(char *cmd, GHashTable *ht_p2p, GHashTable *ht_p2d) +{ + FILE *file; + int ret, i; + char *line = NULL, *dline = NULL, *pack = NULL, *date = NULL; + char *nm, *vr, *rl, *c, *p; + size_t size = 0; + char name[] = "Name"; + char version[] = "Version"; + char release[] = "Release"; + char delim[] = " "; + + file = popen(cmd, "r"); + while ((ret = getline(&line, &size, file)) >= 0 && size) { + pack = nm = vr = rl = NULL; + if (!(nm = lookup_part(name, line))) + goto cleanup; + if ((ret = getline(&line, &size, file)) < 0 && !size) { + goto cleanup; + } + if (!(vr = lookup_part(version, line))) { + goto cleanup; + } + if ((ret = getline(&line, &size, file)) < 0 && !size) { + goto cleanup; + } + if (!(rl = lookup_part(release, line))) { + goto cleanup; + } + if (asprintf(&pack, "%s-%s-%s", nm, vr, rl) < 0) { + goto cleanup; + } + /* using p instead of pack to keep freeing the hashtables uniform */ + if (!(p = g_hash_table_lookup(ht_p2p, pack))) + goto cleanup; + + while ((ret = getline(&dline, &size, file)) >= 0 && size) { + if (strncmp("*", dline, 1)) + continue; + /* twice to skip the leading '*' */ + c = strtok(dline, delim); + c = strtok(NULL, delim); + if (!(date = strdup(c))) { + goto cleanup; + } + for (i = 0; i < 3; i++) { + c = strtok(NULL, delim); + if ((ret = append(&date, c, " ")) < 0) + goto cleanup; + } + g_hash_table_insert(ht_p2d, p, date); + date = NULL; + break; + } + cleanup: + free(nm); + free(vr); + free(rl); + free(pack); + free(date); + } + pclose(file); + free(dline); + free(line); + + return; +} + +char *get_package_info(char *appfile, char *dump_text) +{ + GList *l, *files = NULL, *hfiles = NULL, *tmpl = NULL; + GHashTable *ht_f2f, *ht_f2p, *ht_p2p, *ht_p2d; + char *c1, *cmd = NULL, *out = NULL; + char find_pkg[] = "rpm -qf --queryformat \"%{NAME}-%{VERSION}-%{RELEASE}\" "; + char find_date[] = "rpm -qi --changelog"; + char dev_null[] = "2>/dev/null"; + + if (!(ht_f2f = g_hash_table_new(g_str_hash, g_str_equal))) + return NULL; + if (!(ht_f2p = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free))) + return NULL; + if (!(ht_p2p = g_hash_table_new(g_str_hash, g_str_equal))) + return NULL; + if (!(ht_p2d = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, free))) + return NULL; + if (!(files = get_core_file_list(appfile, dump_text))) + return NULL; + + /* get files in hash to remove duplicates */ + for (l = files; l; l = l->next) + if (!g_hash_table_lookup(ht_f2f, l->data)) + g_hash_table_insert(ht_f2f, l->data, l->data); + + hfiles = g_hash_table_get_keys(ht_f2f); + + /* run through files one at a time in case some files don't have packages and it */ + /* isn't guaranteed we will see the error correspond with the file we are testing */ + for (l = hfiles; l; l = l->next) { + if (asprintf(&cmd, "%s%s %s", find_pkg, (char *) l->data, dev_null) < 0) + goto clean_up; + c1 = run_cmd(cmd); + free(cmd); + cmd = NULL; + + if (c1 && strlen(c1) > 0) + g_hash_table_insert(ht_f2p, l->data, c1); + else { + g_hash_table_insert(ht_f2p, l->data, NULL); + free(c1); } - pclose(file); } - if (asprintf(&command, "rpm -q --whatprovides %s --queryformat \"%%{ARCH}\"", appfile) < 0) { - arch = strdup("Unknown"); - } else { - file = popen(command, "r"); - free(command); - ret = getline(&line, &size, file); - if ((!size) || (ret < 0)) { - arch = strdup("Unknown"); - } else { - c = strchr(line, '\n'); - if (c) *c = 0; - arch = strdup(line); - } - pclose(file); + tmpl = g_hash_table_get_values(ht_f2p); + for (l = tmpl; l; l = l->next) { + if (l->data && !g_hash_table_lookup(ht_p2p, l->data)) + g_hash_table_insert(ht_p2p, l->data, l->data); } - free(line); + + g_list_free(tmpl); + tmpl = g_hash_table_get_keys(ht_p2p); + if (asprintf(&cmd, "%s", find_date) < 0) + goto clean_up; + for (l = tmpl; l; l = l->next) { + append(&cmd, l->data, " "); + } + g_list_free(tmpl); + build_times(cmd, ht_p2p, ht_p2d); + free(cmd); + + if (!(out = strdup(""))) + goto clean_up; + for (l = hfiles; l; l = l->next) { + if (append(&out, l->data, "") < 0) + continue; + + if (!(c1 = g_hash_table_lookup(ht_f2p, l->data))) { + if (append(&out, "\n", "") < 0) + goto clean_out; + continue; + } else + if (append(&out, c1, ":") < 0) + goto clean_out; + + if (!(c1 = g_hash_table_lookup(ht_p2d, c1))) { + if (append(&out, "\n", "") < 0) + goto clean_out; + continue; + } else + if (append(&out, c1, ":") < 0) + goto clean_out; + + if (append(&out, "\n", "") < 0) + goto clean_out; + } + goto clean_up; + +clean_out: + free(out); + out = NULL; + +clean_up: + g_hash_table_destroy(ht_p2d); + g_hash_table_destroy(ht_p2p); + g_hash_table_destroy(ht_f2p); + g_hash_table_destroy(ht_f2f); + g_list_free_full(files, free); + g_list_free(hfiles); + g_list_free(tmpl); + + return out; } char *signame(int sig) @@ -266,44 +457,29 @@ char *build_core_header(char *appfile, char *corefile) { char *release = get_release(); char *kernel = get_kernel(); long int time = get_time(corefile); - char *private = private_report ? "private: yes\n" : ""; - - get_package_info(appfile); ret = asprintf(&result, "analyzer: corewatcher-gdb\n" - "architecture: %s\n" - "component: %s\n" "coredump: %s\n" "executable: %s\n" "kernel: %s\n" - "package: %s\n" "reason: Process %s was killed by signal %d (%s)\n" "release: %s\n" "build: %s\n" "time: %lu\n" - "uid: %d\n" - "%s" - "\nbacktrace\n-----\n", - arch, - component, + "uid: %d\n", corefile, appfile, kernel, - package, appfile, sig, signame(sig), release, build, time, - uid, - private); + uid); free(kernel); - free(package); free(release); free(build); - free(component); - free(arch); if (ret < 0) result = strdup("Unknown"); @@ -346,10 +522,13 @@ void wrapper_scan(char *command) struct oops *extract_core(char *corefile) { struct oops *oops; - char *command = NULL, *c1 = NULL, *c2 = NULL, *line = NULL; - char *coredump = NULL; + int ret; + char *command = NULL, *h1 = NULL, *h2 = NULL, *c1 = NULL, *c2 = NULL, *line = NULL; + char *coredump = NULL, *text = NULL; char *appfile; FILE *file; + char *private = private_report ? "private: yes\n" : ""; + coredump = find_coredump(corefile); if (!coredump) @@ -370,12 +549,11 @@ struct oops *extract_core(char *corefile) } wrapper_scan(command); - c1 = build_core_header(appfile, corefile); + h1 = build_core_header(appfile, corefile); file = popen(command, "r"); while (!feof(file)) { size_t size = 0; - int ret; c2 = c1; free(line); @@ -399,21 +577,40 @@ struct oops *extract_core(char *corefile) free(c2); } else { /* keep going even if asprintf has errors */ - asprintf(&c1, "%s", line); + ret = asprintf(&c1, "%s", line); } } if (line) free(line); pclose(file); free(command); + + if (!(h2 = get_package_info(appfile, c1))) + h2 = strdup("Unknown"); + + ret = asprintf(&text, + "%s" + "package-info\n-----\n" + "%s" + "\n-----\n" + "%s" + "\nbacktrace\n-----\n" + "%s", + h1, h2, private, c1); + if (ret < 0) + text = NULL; + free(h1); + free(h2); + free(c1); + oops = malloc(sizeof(struct oops)); if (!oops) { - free(c1); + free(text); return NULL; } memset(oops, 0, sizeof(struct oops)); oops->application = strdup(appfile); - oops->text = c1; + oops->text = text; oops->filename = strdup(corefile); return oops; } -- 2.7.4