/* SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #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 ]\n\n" "where, COMMAND is:\n" " list = lists all the event logs in human readable format\n\n" "ARGS\n" "-f, --file 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; }