summaryrefslogtreecommitdiff
path: root/util/cbfstool/elogtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/cbfstool/elogtool.c')
-rw-r--r--util/cbfstool/elogtool.c161
1 files changed, 161 insertions, 0 deletions
diff --git a/util/cbfstool/elogtool.c b/util/cbfstool/elogtool.c
new file mode 100644
index 0000000000..ba59eac514
--- /dev/null
+++ b/util/cbfstool/elogtool.c
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <common.h>
+#include <commonlib/bsd/elog.h>
+#include <flashrom.h>
+
+#include "eventlog.h"
+
+enum elogtool_return {
+ ELOGTOOL_EXIT_SUCCESS = 0,
+ ELOGTOOL_EXIT_BAD_ARGS,
+ ELOGTOOL_EXIT_BAD_INPUT_PATH,
+ ELOGTOOL_EXIT_NOT_ENOUGH_MEMORY,
+ ELOGTOOL_EXIT_INVALID_ELOG_FORMAT,
+};
+
+static struct option long_options[] = {
+ {"file", required_argument, 0, 'f'},
+ {"help", no_argument, 0, 'h'},
+ {NULL, 0, 0, 0},
+};
+
+static void usage(char *invoked_as)
+{
+ fprintf(stderr, "elogtool: list elog events\n\n"
+ "USAGE:\n"
+ "\t%s COMMAND [-f <filename>]\n\n"
+ "where, COMMAND is:\n"
+ " list = lists all the event logs in human readable format\n\n"
+ "ARGS\n"
+ "-f, --file <filename> Input file that holds event log partition.\n"
+ " If empty it will try to read from the RW_ELOG ROM region\n"
+ "-h, --help Print this help\n",
+ invoked_as);
+}
+
+// If filename is empty, read RW_ELOG from flashrom. Otherwise read the RW_ELOG from a file.
+// Buffer must be freed by caller.
+static int elog_read(const char *filename, struct buffer *buffer)
+{
+ if (filename == NULL) {
+ uint8_t *buf;
+ uint32_t buf_size;
+
+ if (flashrom_read(FLASHROM_PROGRAMMER_INTERNAL_AP, "RW_ELOG", &buf, &buf_size)
+ != VB2_SUCCESS) {
+ fprintf(stderr, "Could not read RW_ELOG region using flashrom\n");
+ return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ }
+ buffer_init(buffer, NULL, buf, buf_size);
+ } else {
+ if (buffer_from_file(buffer, filename) != 0) {
+ fprintf(stderr, "Could not read input file: %s\n", filename);
+ return ELOGTOOL_EXIT_BAD_INPUT_PATH;
+ }
+ }
+
+ return 0;
+}
+
+static int elog_list_events(const struct buffer *buf)
+{
+ const struct event_header *event;
+ const void *data;
+ uint32_t data_len;
+ unsigned int count = 0;
+
+ data = buffer_get(buf);
+ data_len = buffer_size(buf);
+
+ if (elog_verify_header(data) != CB_SUCCESS) {
+ fprintf(stderr, "FATAL: Invalid elog header\n");
+ return ELOGTOOL_EXIT_INVALID_ELOG_FORMAT;
+ }
+
+ /* Point to first event */
+ event = (const struct event_header *)(data + sizeof(struct elog_header));
+
+ while ((const void *)(event) < data + data_len) {
+ if (event->type == ELOG_TYPE_EOL || event->length == 0)
+ break;
+
+ eventlog_print_event(event, count);
+ event = elog_get_next_event(event);
+ count++;
+ }
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}
+
+static int cmd_list(const char *filename)
+{
+ int ret;
+
+ // Returned buffer must be freed.
+ struct buffer buf;
+ ret = elog_read(filename, &buf);
+ if (ret != 0)
+ return ret;
+
+ ret = elog_list_events(&buf);
+
+ buffer_delete(&buf);
+ return ret;
+}
+
+
+int main(int argc, char **argv)
+{
+ int argflag;
+ char *input_file = NULL;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ while (1) {
+ int option_index;
+ argflag = getopt_long(argc, argv, "hf:", long_options, &option_index);
+ if (argflag == -1)
+ break;
+
+ switch (argflag) {
+ case 'h':
+ case '?':
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_SUCCESS;
+
+ case 'f':
+ if (!optarg) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ input_file = optarg;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* At least one command must be available. */
+ if (optind >= argc) {
+ usage(argv[0]);
+ return ELOGTOOL_EXIT_BAD_ARGS;
+ }
+
+ if (!strcmp(argv[optind], "list"))
+ return cmd_list(input_file);
+
+ return ELOGTOOL_EXIT_SUCCESS;
+}