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