ACK: [PATCH] v2 - Introduce olog scan, to check OPAL msglog.
Alex Hung
alex.hung at canonical.com
Fri Apr 1 14:26:28 UTC 2016
On 03/25/2016 09:22 AM, Deb McLemore wrote:
> This feature adds the olog option which will scan for patterns defined
> in the olog.json data file and compare against the PPC OPAL firmware
> msglog. Extending similar capabilities of the klog functionality,
> this feature also allows customization to specify any file as the
> source and any JSON data file as the patterns.
>
> Signed-off-by: Deb McLemore <debmc at linux.vnet.ibm.com>
> ---
> data/Makefile.am | 2 +-
> data/olog.json | 33 +++++
> src/Makefile.am | 1 +
> src/kernel/olog/olog.c | 96 +++++++++++++
> src/lib/include/fwts.h | 6 +
> src/lib/include/fwts_framework.h | 3 +
> src/lib/include/fwts_klog.h | 6 +
> src/lib/include/fwts_olog.h | 36 +++++
> src/lib/src/Makefile.am | 1 +
> src/lib/src/fwts_framework.c | 86 +++++++-----
> src/lib/src/fwts_klog.c | 15 +-
> src/lib/src/fwts_olog.c | 286 +++++++++++++++++++++++++++++++++++++++
> src/lib/src/fwts_stringextras.c | 4 +
> 13 files changed, 535 insertions(+), 40 deletions(-)
> create mode 100644 data/olog.json
> create mode 100644 src/kernel/olog/olog.c
> create mode 100644 src/lib/include/fwts_olog.h
> create mode 100644 src/lib/src/fwts_olog.c
>
> diff --git a/data/Makefile.am b/data/Makefile.am
> index f9ee508..525dede 100644
> --- a/data/Makefile.am
> +++ b/data/Makefile.am
> @@ -1,2 +1,2 @@
> fwtsdatadir = $(pkgdatadir)
> -fwtsdata_DATA = klog.json syntaxcheck.json
> +fwtsdata_DATA = klog.json syntaxcheck.json olog.json
> diff --git a/data/olog.json b/data/olog.json
> new file mode 100644
> index 0000000..3dbd63c
> --- /dev/null
> +++ b/data/olog.json
> @@ -0,0 +1,33 @@
> +{
> + "olog_error_warning_patterns":
> + [
> + {
> + "compare_mode": "string",
> + "log_level": "LOG_LEVEL_CRITICAL",
> + "pattern": "CRITICAL",
> + "advice": "SAMPLE TEXT -> Check your log for this condition and give some specific investigative and action steps.",
> + "label": "OLOG_Filter_GROUP1"
> + },
> + {
> + "compare_mode": "string",
> + "log_level": "LOG_LEVEL_HIGH",
> + "pattern": "STOP",
> + "advice": "SAMPLE TEXT -> Check your log for this condition and give some specific investigative and action steps.",
> + "label": "OLOG_Filter_GROUPA"
> + },
> + {
> + "compare_mode": "string",
> + "log_level": "LOG_LEVEL_MEDIUM",
> + "pattern": "STOP",
> + "advice": "SAMPLE TEXT -> Check your log for this condition and give some specific investigative and action steps.",
> + "label": "OLOG_Filter_GROUPB"
> + },
> + {
> + "compare_mode": "regex",
> + "log_level": "LOG_LEVEL_LOW",
> + "pattern": "Trying.*",
> + "advice": "SAMPLE TEXT -> This needs further investigation and review, please take xyz corrective action.",
> + "label": "OLOG_Filter_GROUPC"
> + }
> + ]
> +}
> diff --git a/src/Makefile.am b/src/Makefile.am
> index e1332a2..afe7323 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -116,6 +116,7 @@ fwts_SOURCES = main.c \
> dmi/dmicheck/dmicheck.c \
> hotkey/hotkey/hotkey.c \
> kernel/klog/klog.c \
> + kernel/olog/olog.c \
> kernel/oops/oops.c \
> kernel/version/version.c \
> pci/aspm/aspm.c \
> diff --git a/src/kernel/olog/olog.c b/src/kernel/olog/olog.c
> new file mode 100644
> index 0000000..d8487f0
> --- /dev/null
> +++ b/src/kernel/olog/olog.c
> @@ -0,0 +1,96 @@
> +/*
> + * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> + *
> + * 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 "fwts.h"
> +
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +static fwts_list *olog;
> +
> +static int olog_init(fwts_framework *fw)
> +{
> + if (fw->olog) {
> + olog = fwts_file_open_and_read(fw->olog);
> + if (olog == NULL) {
> + fwts_log_error(fw, "OLOG -o file %s may not exist, please check that the file exits and is good.", fw->olog);
> + return FWTS_ERROR;
> + }
> + }
> + else {
> + olog = fwts_olog_read(fw);
> + if (olog == NULL) {
> + fwts_log_error(fw, "OLOG without any parameters on the platform you are running does nothing, please specify -o for custom log analysis.\n");
> + fwts_log_error(fw, "PPC supports dump and analysis of the default firmware logs.\n");
> + return FWTS_ERROR;
> + }
> + }
> +
> + return FWTS_OK;
> +}
> +
> +static int olog_deinit(fwts_framework *fw)
> +{
> + FWTS_UNUSED(fw);
> +
> + fwts_klog_free(olog);
> +
> + return FWTS_OK;
> +}
> +
> +static void olog_progress(fwts_framework *fw, int progress)
> +{
> + fwts_progress(fw, progress);
> +}
> +
> +static int olog_test1(fwts_framework *fw)
> +{
> + int errors = 0;
> +
> + if (fwts_olog_firmware_check(fw, olog_progress, olog, &errors)) {
> + fwts_log_error(fw, "Problem in the OLOG processing, see earlier in this log for details on the problem.");
> + return FWTS_ERROR;
> + }
> +
> + if (errors > 0)
> + /* Checks will log errors as failures automatically */
> + fwts_log_info(fw, "OLOG scan and analysis found %d unique issue(s).",
> + errors);
> + else
> + fwts_passed(fw, "OLOG scan and analysis passed.");
> +
> + return FWTS_OK;
> +}
> +
> +static fwts_framework_minor_test olog_tests[] = {
> + { olog_test1, "OLOG scan and analysis checks results." },
> + { NULL, NULL }
> +};
> +
> +static fwts_framework_ops olog_ops = {
> + .description = "Run OLOG scan and analysis checks.",
> + .init = olog_init,
> + .deinit = olog_deinit,
> + .minor_tests = olog_tests
> +};
> +
> +FWTS_REGISTER("olog", &olog_ops, FWTS_TEST_EARLY, FWTS_FLAG_BATCH)
> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
> index d708201..cbc417e 100644
> --- a/src/lib/include/fwts.h
> +++ b/src/lib/include/fwts.h
> @@ -1,5 +1,6 @@
> /*
> * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> @@ -38,6 +39,10 @@
> #define FWTS_ARCH_S390X 1
> #endif
>
> +#if defined(__PPC64__)
> +#define FWTS_HAS_ACPI 0
> +#define FWTS_HAS_UEFI 0
> +#endif
>
> #define FWTS_UNUSED(var) (void)var
>
> @@ -67,6 +72,7 @@
> #include "fwts_gpe.h"
> #include "fwts_iasl.h"
> #include "fwts_klog.h"
> +#include "fwts_olog.h"
> #include "fwts_pipeio.h"
> #include "fwts_stringextras.h"
> #include "fwts_tty.h"
> diff --git a/src/lib/include/fwts_framework.h b/src/lib/include/fwts_framework.h
> index c9ea4bb..6c2332a 100644
> --- a/src/lib/include/fwts_framework.h
> +++ b/src/lib/include/fwts_framework.h
> @@ -1,5 +1,6 @@
> /*
> * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> @@ -117,7 +118,9 @@ typedef struct fwts_framework {
> char *acpi_table_path; /* path to raw ACPI tables */
> char *acpi_table_acpidump_file; /* path to ACPI dump file */
> char *klog; /* path to dump of kernel log */
> + char *olog; /* path to OLOG */
> char *json_data_path; /* path to application json data files, e.g. json klog data */
> + char *json_data_file; /* json file to use for olog analysis */
>
> fwts_framework_flags flags;
>
> diff --git a/src/lib/include/fwts_klog.h b/src/lib/include/fwts_klog.h
> index db68232..3f0d431 100644
> --- a/src/lib/include/fwts_klog.h
> +++ b/src/lib/include/fwts_klog.h
> @@ -26,6 +26,7 @@
> #include "fwts_list.h"
> #include "fwts_framework.h"
> #include "fwts_log.h"
> +#include "fwts_json.h"
>
> #define KERN_WARNING 0x00000001
> #define KERN_ERROR 0x00000002
> @@ -47,6 +48,7 @@ typedef struct {
> bool compiled_ok;
> } fwts_klog_pattern;
>
> +
> typedef void (*fwts_klog_progress_func)(fwts_framework *fw, int percent);
> typedef void (*fwts_klog_scan_func)(fwts_framework *fw, char *line, int repeated, char *prevline, void *private, int *errors);
>
> @@ -63,4 +65,8 @@ int fwts_klog_regex_find(fwts_framework *fw, fwts_list *klog, char *pattern);
> char *fwts_klog_remove_timestamp(char *text);
> int fwts_klog_write(fwts_framework *fw, const char *msg);
>
> +fwts_compare_mode fwts_klog_compare_mode_str_to_val(const char *str);
> +char *fwts_klog_unique_label(const char *str);
> +const char *fwts_json_str(fwts_framework *fw, const char *table, int index, json_object *obj, const char *key, bool log_error);
> +
> #endif
> diff --git a/src/lib/include/fwts_olog.h b/src/lib/include/fwts_olog.h
> new file mode 100644
> index 0000000..7df7e74
> --- /dev/null
> +++ b/src/lib/include/fwts_olog.h
> @@ -0,0 +1,36 @@
> +/*
> + * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> + *
> + * 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.
> + *
> + */
> +
> +#ifndef __FWTS_OPAL_H__
> +#define __FWTS_OPAL_H__
> +
> +#include <sys/types.h>
> +#include <regex.h>
> +
> +#include "fwts_list.h"
> +#include "fwts_framework.h"
> +#include "fwts_log.h"
> +
> +fwts_list *fwts_olog_read(fwts_framework *fw);
> +
> +typedef void (*fwts_olog_progress_func)(fwts_framework *fw, int percent);
> +int fwts_olog_firmware_check(fwts_framework *fw, fwts_olog_progress_func progress, fwts_list *olog, int *errors);
> +
> +#endif
> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
> index 5d63804..5302851 100644
> --- a/src/lib/src/Makefile.am
> +++ b/src/lib/src/Makefile.am
> @@ -55,6 +55,7 @@ libfwts_la_SOURCES = \
> fwts_ioport.c \
> fwts_keymap.c \
> fwts_klog.c \
> + fwts_olog.c \
> fwts_list.c \
> fwts_log.c \
> fwts_log_html.c \
> diff --git a/src/lib/src/fwts_framework.c b/src/lib/src/fwts_framework.c
> index fcf2e86..2bfc753 100644
> --- a/src/lib/src/fwts_framework.c
> +++ b/src/lib/src/fwts_framework.c
> @@ -1,5 +1,6 @@
> /*
> * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> *
> * This program is free software; you can redistribute it and/or
> * modify it under the terms of the GNU General Public License
> @@ -94,6 +95,7 @@ static fwts_option fwts_framework_options[] = {
> { "show-progress", "p", 0, "Output test progress report to stderr." },
> { "show-tests", "s", 0, "Show available tests." },
> { "klog", "k:", 1, "Specify kernel log file rather than reading it from the kernel, e.g. --klog=dmesg.log" },
> + { "olog", "o:", 1, "Specify Other logs to be analyzed, main usage is for custom log analysis, best to use custom json file for pattern matching, e.g. -o /var/log/my_opal_msglog --json-data-file=olog.json --json-data-path=/home/myuser, on PPC this will default to dumping the OPAL msglog for analysis." },
> { "log-width", "w:", 1, "Define the output log width in characters." },
> { "lspci", "", 1, "Specify path to lspci, e.g. --lspci=path." },
> { "batch", "b", 0, "Run non-Interactive tests." },
> @@ -113,6 +115,7 @@ static fwts_option fwts_framework_options[] = {
> { "show-tests-full", "", 0, "Show available tests including all minor tests." },
> { "utils", "u", 0, "Run Utility 'tests'." },
> { "json-data-path", "j:", 1, "Specify path to fwts json data files - default is /usr/share/fwts." },
> + { "json-data-file", "J:", 1, "Specify the file to use for pattern matching on --olog, you may need to specify the json-data-path also if non-default location." },
> { "disassemble-aml", "", 2, "Disassemble AML from DSDT and SSDT tables." },
> { "log-type", "", 1, "Specify log type (plaintext, json, html or xml)." },
> { "unsafe", "U", 0, "Unsafe tests (tests that can potentially cause kernel oopses)." },
> @@ -136,6 +139,7 @@ static fwts_list fwts_framework_test_list = FWTS_LIST_INIT;
> static const char *fwts_copyright[] = {
> "Some of this work - Copyright (c) 1999 - 2016, Intel Corp. All rights reserved.",
> "Some of this work - Copyright (c) 2010 - 2016, Canonical.",
> + "Some of this work - Copyright (c) 2016 IBM.",
> NULL
> };
>
> @@ -1185,71 +1189,77 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
> case 9: /* --klog */
> fwts_framework_strdup(&fw->klog, optarg);
> break;
> - case 10: /* --log-width=N */
> + case 10: /* --olog */
> + fwts_framework_strdup(&fw->olog, optarg);
> + break;
> + case 11: /* --log-width=N */
> fwts_log_set_line_width(atoi(optarg));
> break;
> - case 11: /* --lspci=pathtolspci */
> + case 12: /* --lspci=pathtolspci */
> fwts_framework_strdup(&fw->lspci, optarg);
> break;
> - case 12: /* --batch */
> + case 13: /* --batch */
> fw->flags |= FWTS_FLAG_BATCH;
> break;
> - case 13: /* --interactive */
> + case 14: /* --interactive */
> fw->flags |= FWTS_FLAG_INTERACTIVE;
> break;
> - case 14: /* --force-clean */
> + case 15: /* --force-clean */
> fw->flags |= FWTS_FLAG_FORCE_CLEAN;
> break;
> - case 15: /* --version */
> + case 16: /* --version */
> fwts_framework_show_version(stdout, argv[0]);
> return FWTS_COMPLETE;
> - case 16: /* --dump */
> + case 17: /* --dump */
> fw->flags |= FWTS_FLAG_DUMP;
> break;
> - case 17: /* --table-path */
> + case 18: /* --table-path */
> fwts_framework_strdup(&fw->acpi_table_path, optarg);
> break;
> - case 18: /* --batch-experimental */
> + case 19: /* --batch-experimental */
> fw->flags |= FWTS_FLAG_BATCH_EXPERIMENTAL;
> break;
> - case 19: /* --interactive-experimental */
> + case 20: /* --interactive-experimental */
> fw->flags |= FWTS_FLAG_INTERACTIVE_EXPERIMENTAL;
> break;
> - case 20: /* --power-states */
> + case 21: /* --power-states */
> fw->flags |= FWTS_FLAG_POWER_STATES;
> break;
> - case 21: /* --all */
> + case 22: /* --all */
> fw->flags |= FWTS_FLAG_RUN_ALL;
> break;
> - case 22: /* --show-progress-dialog */
> + case 23: /* --show-progress-dialog */
> fw->flags = (fw->flags &
> ~(FWTS_FLAG_QUIET |
> FWTS_FLAG_SHOW_PROGRESS))
> | FWTS_FLAG_SHOW_PROGRESS_DIALOG;
> break;
> - case 23: /* --skip-test */
> + case 24: /* --skip-test */
> if (fwts_framework_skip_test_parse(optarg, &tests_to_skip) != FWTS_OK)
> return FWTS_COMPLETE;
> break;
> - case 24: /* --quiet */
> + case 25: /* --quiet */
> fw->flags = (fw->flags &
> ~(FWTS_FLAG_SHOW_PROGRESS |
> FWTS_FLAG_SHOW_PROGRESS_DIALOG))
> | FWTS_FLAG_QUIET;
> break;
> - case 25: /* --dumpfile */
> + case 26: /* --dumpfile */
> fwts_framework_strdup(&fw->acpi_table_acpidump_file, optarg);
> break;
> - case 26: /* --show-tests-full */
> + case 27: /* --show-tests-full */
> fw->flags |= FWTS_FLAG_SHOW_TESTS_FULL;
> break;
> - case 27: /* --utils */
> + case 28: /* --utils */
> fw->flags |= FWTS_FLAG_UTILS;
> break;
> - case 28: /* --json-data-path */
> + case 29: /* --json-data-path */
> fwts_framework_strdup(&fw->json_data_path, optarg);
> break;
> - case 29: /* --disassemble-aml */
> + case 30: /* --json-data-file */
> + fwts_framework_strdup(&fw->json_data_file, optarg);
> + break;
> + case 31: /* --disassemble-aml */
> #if defined(FWTS_HAS_ACPI)
> fwts_iasl_disassemble_all_to_file(fw, optarg);
> return FWTS_COMPLETE;
> @@ -1257,52 +1267,52 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
> fprintf(stderr, "option not available on this architecture\n");
> return FWTS_ERROR;
> #endif
> - case 30: /* --log-type */
> + case 32: /* --log-type */
> if (fwts_framework_log_type_parse(fw, optarg) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 31: /* --unsafe */
> + case 33: /* --unsafe */
> fw->flags |= FWTS_FLAG_UNSAFE;
> break;
> - case 32: /* --filter-error-discard */
> + case 34: /* --filter-error-discard */
> if (fwts_framework_filter_error_parse(optarg, &fw->errors_filter_discard) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 33: /* --filter-error-keep */
> + case 35: /* --filter-error-keep */
> if (fwts_framework_filter_error_parse(optarg, &fw->errors_filter_keep) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 34: /* --acpica-debug */
> + case 36: /* --acpica-debug */
> fw->flags |= FWTS_FLAG_ACPICA_DEBUG;
> break;
> - case 35: /* --acpica */
> + case 37: /* --acpica */
> if (fwts_framework_acpica_parse(fw, optarg) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 36: /* --uefitests */
> + case 38: /* --uefitests */
> fw->flags |= FWTS_FLAG_TEST_UEFI;
> break;
> - case 37: /* --rsdp */
> + case 39: /* --rsdp */
> fw->rsdp = (void *)strtoul(optarg, NULL, 0);
> break;
> - case 38: /* --pm-method */
> + case 40: /* --pm-method */
> if (fwts_framework_pm_method_parse(fw, optarg) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 39: /* --show-tests-categories */
> + case 41: /* --show-tests-categories */
> fw->flags |= FWTS_FLAG_SHOW_TESTS_CATEGORIES;
> break;
> - case 40: /* --acpitests */
> + case 42: /* --acpitests */
> fw->flags |= FWTS_FLAG_TEST_ACPI;
> break;
> - case 41: /* --acpicompliance */
> + case 43: /* --acpicompliance */
> fw->flags |= FWTS_FLAG_TEST_COMPLIANCE_ACPI;
> break;
> - case 42: /* --log-level */
> + case 44: /* --log-level */
> if (fwts_framework_ll_parse(fw, optarg) != FWTS_OK)
> return FWTS_ERROR;
> break;
> - case 43: /* --arch */
> + case 45: /* --arch */
> if (fwts_framework_an_parse(fw, optarg) != FWTS_OK)
> return FWTS_ERROR;
> break;
> @@ -1336,11 +1346,17 @@ int fwts_framework_options_handler(fwts_framework *fw, int argc, char * const ar
> case 'j': /* --json-data-path */
> fwts_framework_strdup(&fw->json_data_path, optarg);
> break;
> + case 'J': /* --json-data-file */
> + fwts_framework_strdup(&fw->json_data_file, optarg);
> + break;
> case 'k': /* --klog */
> fwts_framework_strdup(&fw->klog, optarg);
> break;
> case 'l': /* --lp-flags */
> break;
> + case 'o': /* --olog */
> + fwts_framework_strdup(&fw->olog, optarg);
> + break;
> case 'p': /* --show-progress */
> fw->flags = (fw->flags &
> ~(FWTS_FLAG_QUIET |
> @@ -1582,7 +1598,9 @@ tidy_close:
> free(fw->lspci);
> free(fw->results_logname);
> free(fw->klog);
> + free(fw->olog);
> free(fw->json_data_path);
> + free(fw->json_data_file);
>
> fwts_list_free_items(&fw->errors_filter_discard, NULL);
> fwts_list_free_items(&fw->errors_filter_keep, NULL);
> diff --git a/src/lib/src/fwts_klog.c b/src/lib/src/fwts_klog.c
> index b5f0965..63918e7 100644
> --- a/src/lib/src/fwts_klog.c
> +++ b/src/lib/src/fwts_klog.c
> @@ -229,7 +229,7 @@ int fwts_klog_scan(fwts_framework *fw,
> return FWTS_OK;
> }
>
> -static char *fwts_klog_unique_label(const char *str)
> +char *fwts_klog_unique_label(const char *str)
> {
> static char buffer[1024];
> const char *src = str;
> @@ -325,7 +325,7 @@ void fwts_klog_scan_patterns(fwts_framework *fw,
> * fwts_klog_compare_mode_str_to_val()
> * convert compare mode strings (from json database) to compare_mode values
> */
> -static fwts_compare_mode fwts_klog_compare_mode_str_to_val(const char *str)
> +fwts_compare_mode fwts_klog_compare_mode_str_to_val(const char *str)
> {
> if (strcmp(str, "regex") == 0)
> return FWTS_COMPARE_REGEX;
> @@ -340,7 +340,7 @@ static fwts_compare_mode fwts_klog_compare_mode_str_to_val(const char *str)
> * given a key, fetch the string value associated with this object
> * and report an error if it cannot be found.
> */
> -static const char *fwts_json_str(
> +const char *fwts_json_str(
> fwts_framework *fw,
> const char *table,
> int index,
> @@ -385,14 +385,19 @@ static int fwts_klog_check(fwts_framework *fw,
> fwts_klog_pattern *patterns;
> char json_data_path[PATH_MAX];
>
> - snprintf(json_data_path, sizeof(json_data_path), "%s/%s", fw->json_data_path, KLOG_DATA_JSON_FILE);
> + if (fw->json_data_file) {
> + snprintf(json_data_path, sizeof(json_data_path), "%s/%s", fw->json_data_path,(fw->json_data_file));
> + }
> + else { /* use the hard coded KLOG JSON as default */
> + snprintf(json_data_path, sizeof(json_data_path), "%s/%s", fw->json_data_path, KLOG_DATA_JSON_FILE);
> + }
>
> /*
> * json_object_from_file() can fail when files aren't readable
> * so check if we can open for read before calling json_object_from_file()
> */
> if ((fd = open(json_data_path, O_RDONLY)) < 0) {
> - fwts_log_error(fw, "Cannot read file %s.", json_data_path);
> + fwts_log_error(fw, "Cannot read file %s, check the path and check that the file exists, you may need to specify -j or -J.", json_data_path);
> return FWTS_ERROR;
> }
> close(fd);
> diff --git a/src/lib/src/fwts_olog.c b/src/lib/src/fwts_olog.c
> new file mode 100644
> index 0000000..be13ee6
> --- /dev/null
> +++ b/src/lib/src/fwts_olog.c
> @@ -0,0 +1,286 @@
> +/*
> + * Copyright (C) 2010-2016 Canonical
> + * Some of this work - Copyright (C) 2016 IBM
> + *
> + * 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 <sys/klog.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <sys/types.h>
> +#include <ctype.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <regex.h>
> +#include <fcntl.h>
> +
> +#include "fwts.h"
> +
> +/*
> + * OLOG pattern matching strings data file, data stored in json format
> + */
> +#define OLOG_DATA_JSON_FILE "olog.json"
> +#define MSGLOG_BUFFER_LINE PATH_MAX
> +
> +/* SPECIAL CASE USE for OPEN POWER opal Firmware LOGS */
> +static const char msglog[] = "/sys/firmware/opal/msglog";
> +static const char msglog_outfile[] = "/var/log/opal_msglog";
> +
> +/*
> + * fwts_olog_read(fwts_framework *fw)
> + * read olog log and return as list of lines
> + */
> +fwts_list *fwts_olog_read(fwts_framework *fw)
> +{
> + long len;
> + fwts_list *list;
> + char *buffer;
> + struct stat filestat;
> + long read_actual=0;
> + long write_actual=0;
> + FILE* msglog_f;
> + FILE* msglog_outfile_f;
> +
> +/* Check for the existance of the opal msglog and only if it exists dump it out */
> +/* This makes the use of the OLOG as a custom option and not just for PPC */
> +/* We don't use compiler flags since we want to run this as a custom job cross platform */
> +
> + if (stat(msglog,&filestat)) /* stat fails so not PPC with OPAL msglog and no -o OLOG sent */
> + return NULL;
> +
> +/* Special file handling to sequentially fread the sysfs msglog into a static buffer */
> +/* based on inodes in the stat */
> +/* The sysfs msglog has a 0 byte file size since it is a sysfs object */
> +/* Real size of the sysfs msglog is not in the stat statistics */
> +/* Using the st_blksize (the preferred i/o blksize) */
> +/* st_blocks is zero so must fread block by block */
> +
> +
> + if (!(msglog_f = fopen(msglog, "r"))) /* open the sysfs msglog for read only */
> + goto olog_common_exit;
> +
> + if ((len = filestat.st_blksize) < 1) /* if any size at all continue */
> + goto olog_cleanup_msglog;
> +
> + if ((buffer = calloc(1,len+1)) == NULL)
> + goto olog_cleanup_msglog;
> +
> + if (!(msglog_outfile_f = fopen(msglog_outfile, "w"))) /* create the output file for the sysfs msglog */
> + goto olog_cleanup_msglog; /* so we can dump it out as a real fs file */
> +
> + while (!feof (msglog_f)) {
> + read_actual = fread(buffer,1,len,msglog_f);
> + if (read_actual == len) {
> + write_actual = fwrite(buffer,1,len,msglog_outfile_f);
> + if (!(write_actual == len)) {
> + free(buffer);
> + goto olog_cleanup_common;
> + }
> + } else {
> + if (feof(msglog_f)) {
> + write_actual = fwrite(buffer,1,read_actual,msglog_outfile_f);
> + if (!(write_actual == read_actual)) {
> + free(buffer);
> + goto olog_cleanup_common;
> + }
> + } else
> + break; /* we didn't get a full read and file did not test for EOF so bail */
> + }
> + }
> +
> + free(buffer); /* done with the static small buffer */
> + fclose(msglog_f); /* close the sysfs msglog we don't need it anymore */
> + fclose(msglog_outfile_f); /* close the msglog outfile which was opened for write */
> +
> + /* Now work on the dumped out msglog as a real file system file */
> +
> + if (!(msglog_outfile_f = fopen(msglog_outfile, "r")))
> + goto olog_cleanup_common;
> +
> + if (fseek(msglog_outfile_f,0,SEEK_END))
> + goto olog_cleanup_msglog_outfile;
> +
> + if ((len = ftell(msglog_outfile_f)) == -1)
> + goto olog_cleanup_msglog_outfile;
> +
> + if ((fseek(msglog_outfile_f,0,SEEK_SET)) != 0)
> + goto olog_cleanup_msglog_outfile;
> +
> + if ((buffer = calloc(1, len+1)) == NULL)
> + goto olog_cleanup_msglog_outfile;
> +
> + read_actual = fread(buffer,1,len,msglog_outfile_f);
> + if (read_actual == len) {
> + list = fwts_list_from_text(buffer);
> + free(buffer);
> + fclose(msglog_outfile_f);
> + return list;
> + }
> + else {
> + free(buffer);
> + goto olog_cleanup_msglog_outfile;
> + }
> +
> +olog_cleanup_msglog_outfile:
> + fclose(msglog_outfile_f);
> + goto olog_common_exit;
> +
> +olog_cleanup_msglog:
> + fclose(msglog_f);
> + goto olog_common_exit;
> +
> +olog_cleanup_common:
> + fclose(msglog_f);
> + fclose(msglog_outfile_f);
> +
> +olog_common_exit:
> + fwts_log_error(fw, "Problem with the file handling on the default dumped OPAL msglog, %s, try using -o to specify a specific saved OPAL msglog for analysis.\n", msglog_outfile);
> + return NULL;
> +}
> +
> +
> +static int fwts_olog_check(fwts_framework *fw,
> + const char *table,
> + fwts_olog_progress_func progress,
> + fwts_list *olog,
> + int *errors)
> +{
> + int ret = FWTS_ERROR;
> + int n;
> + int i;
> + int fd;
> + json_object *olog_objs;
> + json_object *olog_table;
> + fwts_klog_pattern *patterns;
> + char json_data_path[PATH_MAX];
> +
> +
> + if (fw->json_data_file) {
> + snprintf(json_data_path, sizeof(json_data_path), "%s/%s", fw->json_data_path,(fw->json_data_file));
> + }
> + else { /* use the hard coded OLOG JSON as default */
> + snprintf(json_data_path, sizeof(json_data_path), "%s/%s", fw->json_data_path, OLOG_DATA_JSON_FILE);
> + }
> +
> + /*
> + * json_object_from_file() can fail when files aren't readable
> + * so check if we can open for read before calling json_object_from_file()
> + */
> + if ((fd = open(json_data_path, O_RDONLY)) < 0) {
> + fwts_log_error(fw, "Cannot read file %s, check the path and check that the file exists, you may need to specify -j or -J.", json_data_path);
> + return FWTS_ERROR;
> + }
> + close(fd);
> +
> + olog_objs = json_object_from_file(json_data_path);
> + if (FWTS_JSON_ERROR(olog_objs)) {
> + fwts_log_error(fw, "Cannot load olog data from %s.", json_data_path);
> + return FWTS_ERROR;
> + }
> +
> +#if JSON_HAS_GET_EX
> + if (!json_object_object_get_ex(olog_objs, table, &olog_table)) {
> + fwts_log_error(fw, "Cannot fetch olog table object '%s' from %s.", table, json_data_path);
> + goto fail_put;
> + }
> +#else
> + olog_table = json_object_object_get(olog_objs, table);
> + if (FWTS_JSON_ERROR(olog_table)) {
> + fwts_log_error(fw, "Cannot fetch olog table object '%s' from %s.", table, json_data_path);
> + goto fail_put;
> + }
> +#endif
> +
> + n = json_object_array_length(olog_table);
> +
> + /* Last entry is null to indicate end, so alloc n+1 items */
> + if ((patterns = calloc(n+1, sizeof(fwts_klog_pattern))) == NULL) {
> + fwts_log_error(fw, "Cannot allocate pattern table.");
> + goto fail_put;
> + }
> +
> + /* Now fetch json objects and compile regex */
> + for (i = 0; i < n; i++) {
> + const char *str;
> + json_object *obj;
> +
> + obj = json_object_array_get_idx(olog_table, i);
> + if (FWTS_JSON_ERROR(obj)) {
> + fwts_log_error(fw, "Cannot fetch %d item from table %s.", i, table);
> + goto fail;
> + }
> + if ((str = fwts_json_str(fw, table, i, obj, "compare_mode", true)) == NULL)
> + goto fail;
> + patterns[i].compare_mode = fwts_klog_compare_mode_str_to_val(str);
> +
> + if ((str = fwts_json_str(fw, table, i, obj, "log_level", true)) == NULL)
> + goto fail;
> + patterns[i].level = fwts_log_str_to_level(str);
> +
> + if ((patterns[i].pattern = fwts_json_str(fw, table, i, obj, "pattern", true)) == NULL)
> + goto fail;
> +
> + if ((patterns[i].advice = fwts_json_str(fw, table, i, obj, "advice", true)) == NULL)
> + goto fail;
> +
> + /* Labels appear in fwts 0.26.0, so are optional with older versions */
> + str = fwts_json_str(fw, table, i, obj, "label", false);
> + if (str) {
> + patterns[i].label = strdup(str);
> + } else {
> + /* if not specified, auto-magically generate */
> + patterns[i].label = strdup(fwts_klog_unique_label(patterns[i].pattern));
> + }
> + if (patterns[i].label == NULL)
> + goto fail;
> +
> + if (patterns[i].compare_mode == FWTS_COMPARE_REGEX) {
> + int rc;
> +
> + rc = regcomp(&patterns[i].compiled, patterns[i].pattern, REG_EXTENDED);
> + if (rc) {
> + fwts_log_error(fw, "Regex %s failed to compile: %d.", patterns[i].pattern, rc);
> + patterns[i].compiled_ok = false;
> + } else {
> + patterns[i].compiled_ok = true;
> + }
> + }
> + }
> + /* We've now collected up the scan patterns, lets scan the log for errors */
> + ret = fwts_klog_scan(fw, olog, fwts_klog_scan_patterns, progress, patterns, errors);
> +
> +fail:
> + for (i = 0; i < n; i++) {
> + if (patterns[i].compiled_ok)
> + regfree(&patterns[i].compiled);
> + if (patterns[i].label)
> + free(patterns[i].label);
> + }
> + free(patterns);
> +fail_put:
> + json_object_put(olog_objs);
> +
> + return ret;
> +}
> +
> +int fwts_olog_firmware_check(fwts_framework *fw, fwts_olog_progress_func progress,
> + fwts_list *olog, int *errors)
> +{
> + return fwts_olog_check(fw, "olog_error_warning_patterns",
> + progress, olog, errors);
> +}
> diff --git a/src/lib/src/fwts_stringextras.c b/src/lib/src/fwts_stringextras.c
> index 17a742c..17d833e 100644
> --- a/src/lib/src/fwts_stringextras.c
> +++ b/src/lib/src/fwts_stringextras.c
> @@ -42,6 +42,10 @@ void fwts_chop_newline(char *str)
>
> while (len > 0 && str[len-1] == ' ')
> str[--len] = '\0';
> +
> + while (len > 0 && str[len-1] == '\r')
> + str[--len] = '\0';
> +
> }
>
> /*
>
Acked-by: Alex Hung <alex.hung at canonical.com>
More information about the fwts-devel
mailing list