blob: ba59eac514c87390c4ee7c5488f642b4d6dfbabd [file] [log] [blame]
/* 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;
}