/* Copyright (C) 2013 Red Hat, 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 "libabrt.h" struct oops_text { unsigned panic_no; unsigned part_no; const char *filename; char *text; }; static struct oops_text *parse_file(const char *filename) { FILE *fp = fopen(filename, "r"); if (!fp) return NULL; char buffer[16 * 1024]; struct oops_text *ot = NULL; if (!fgets(buffer, sizeof(buffer), fp)) goto ret; unsigned n1, n2; int n = sscanf(buffer, "Panic#%u Part%u\n", &n1, &n2); if (n != 2) goto ret; ot = xzalloc(sizeof(*ot)); ot->filename = filename; ot->panic_no = n1; ot->part_no = n2; size_t sz = fread(buffer, 1, sizeof(buffer), fp); ot->text = strndup(buffer, sz); ret: fclose(fp); return ot; } static int compare_oops_texts(const void *a, const void *b) { struct oops_text *aa = *(struct oops_text **)a; struct oops_text *bb = *(struct oops_text **)b; if (aa->panic_no < bb->panic_no) return -1; if (aa->panic_no > bb->panic_no) return 1; if (aa->part_no > bb->part_no) return -1; return (aa->part_no < bb->part_no); } int main(int argc, char **argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "& [-v] [-od] FILE...\n" "\n" "Scans files for split oops message. Can print and/or delete them." ); enum { OPT_v = 1 << 0, OPT_o = 1 << 1, OPT_d = 1 << 2, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL('o', NULL, NULL, _("Print found oopses")), OPT_BOOL('d', NULL, NULL, _("Delete files with found oopses")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(0); struct oops_text **v = xzalloc(sizeof(v[0])); int i = 0; while (*argv) { v[i] = parse_file(*argv); if (v[i]) { v = xrealloc(v, (++i + 1) * sizeof(v[0])); v[i] = NULL; } argv++; } if (i == 0) /* nothing was found */ return 0; qsort(v, i, sizeof(v[0]), compare_oops_texts); if (opts & OPT_o) { struct oops_text **vv = v; while (*vv) { struct oops_text *cur_oops = *vv; fputs(cur_oops->text, stdout); vv++; } } if (opts & OPT_d) { struct oops_text **vv = v; while (*vv) { struct oops_text *cur_oops = *vv; if (unlink(cur_oops->filename) != 0) perror_msg("Can't unlink '%s'", cur_oops->filename); vv++; } } return 0; }