diff options
Diffstat (limited to 'plugins/solidigm/solidigm-internal-logs.c')
-rw-r--r-- | plugins/solidigm/solidigm-internal-logs.c | 116 |
1 files changed, 84 insertions, 32 deletions
diff --git a/plugins/solidigm/solidigm-internal-logs.c b/plugins/solidigm/solidigm-internal-logs.c index 236652a..c604761 100644 --- a/plugins/solidigm/solidigm-internal-logs.c +++ b/plugins/solidigm/solidigm-internal-logs.c @@ -13,6 +13,7 @@ #include <unistd.h> #include <inttypes.h> #include <linux/limits.h> +#include <time.h> #include "common.h" #include "nvme.h" @@ -122,7 +123,7 @@ struct nlog_dump_header4_1 { struct config { __u32 namespace_id; - char *file_prefix; + char *dir_prefix; char *type; bool verbose; }; @@ -222,6 +223,7 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg) __u8 buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; __u8 head_buf[INTERNAL_LOG_MAX_BYTE_TRANSFER]; char file_path[PATH_MAX]; + char file_name[] = "AssertLog.bin"; struct assert_dump_header *ad = (struct assert_dump_header *) head_buf; struct nvme_passthru_cmd cmd = { .opcode = 0xd2, @@ -236,7 +238,8 @@ static int dump_assert_logs(struct nvme_dev *dev, struct config cfg) if (err) return err; - sprintf(file_path, "%s_AssertLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%.*s/%s", + (int) (sizeof(file_path) - sizeof(file_name) - 1), cfg.dir_prefix, file_name); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -291,7 +294,7 @@ static int dump_event_logs(struct nvme_dev *dev, struct config cfg) err = read_header(&cmd, dev_fd(dev)); if (err) return err; - sprintf(file_path, "%s_EventLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%s/EventLog.bin", cfg.dir_prefix); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -387,7 +390,8 @@ static int dump_nlogs(struct nvme_dev *dev, struct config cfg, int core) count = nlog_header->totalnlogs; core_num = core < 0 ? nlog_header->corecount : 0; if (!header_size) { - sprintf(file_path, "%s_NLog.bin", cfg.file_prefix); + snprintf(file_path, sizeof(file_path), "%s/NLog.bin", + cfg.dir_prefix); output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (output < 0) return -errno; @@ -423,25 +427,32 @@ enum telemetry_type { static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetry_type ttype) { - struct nvme_telemetry_log *log = NULL; + _cleanup_free_ struct nvme_telemetry_log *log = NULL; size_t log_size = 0; - int err = 0, output; + int err = 0; __u8 *buffer = NULL; size_t bytes_remaining = 0; enum nvme_telemetry_da da; size_t max_data_tx; char file_path[PATH_MAX]; - char *log_name; + char *file_name; + char *log_descr; + struct stat sb; + + _cleanup_file_ int output = -1; switch (ttype) { case HOSTGENNEW: - log_name = "TelemetryHostGenNew"; + file_name = "lid_0x07_lsp_0x01_lsi_0x0000.bin"; + log_descr = "Generated Host Initiated"; break; case HOSTGENOLD: - log_name = "TelemetryHostGenOld"; + file_name = "lid_0x07_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Existing Host Initiated"; break; case CONTROLLER: - log_name = "TelemetryController"; + file_name = "lid_0x08_lsp_0x00_lsi_0x0000.bin"; + log_descr = "Controller Initiated"; break; default: return -EINVAL; @@ -453,11 +464,6 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr if (max_data_tx > DRIVER_MAX_TX_256K) max_data_tx = DRIVER_MAX_TX_256K; - sprintf(file_path, "%s_%s.bin", cfg.file_prefix, log_name); - output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (output < 0) - return -errno; - switch (ttype) { case HOSTGENNEW: err = nvme_get_telemetry_log(dev_fd(dev), true, false, false, max_data_tx, da, @@ -474,7 +480,20 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr } if (err) - goto tele_close_output; + return err; + + snprintf(file_path, sizeof(file_path), "%s/log_pages", cfg.dir_prefix); + if (!(stat(file_path, &sb) == 0 && S_ISDIR(sb.st_mode))) { + if (mkdir(file_path, 777) != 0) { + perror(file_path); + return -errno; + } + } + + snprintf(file_path, sizeof(file_path), "%s/log_pages/%s", cfg.dir_prefix, file_name); + output = open(file_path, O_WRONLY | O_CREAT | O_TRUNC, 0644); + if (output < 0) + return -errno; bytes_remaining = log_size; buffer = (__u8 *)log; @@ -486,45 +505,49 @@ static int dump_telemetry(struct nvme_dev *dev, struct config cfg, enum telemetr err = -errno; goto tele_close_output; } + bytes_remaining -= bytes_written; buffer += bytes_written; } - printf("Successfully wrote log to %s\n", file_path); + printf("Successfully wrote %s Telemetry log to %s\n", log_descr, file_path); tele_close_output: - free(log); close(output); - return err; } int solidigm_get_internal_log(int argc, char **argv, struct command *command, struct plugin *plugin) { + char folder[PATH_MAX]; + char zip_name[PATH_MAX]; + char *output_path; char sn_prefix[sizeof(((struct nvme_id_ctrl *)0)->sn)+1]; int log_count = 0; int err; - struct nvme_dev *dev; + _cleanup_nvme_dev_ struct nvme_dev *dev = NULL; bool all = false; + time_t t; + struct tm tm; const char *desc = "Get Debug Firmware Logs and save them."; const char *type = "Log type: ALL, CONTROLLERINITTELEMETRY, HOSTINITTELEMETRY, HOSTINITTELEMETRYNOGEN, NLOG, ASSERT, EVENT. Defaults to ALL."; - const char *prefix = "Output file prefix; defaults to device serial number."; + const char *prefix = "Output dir prefix; defaults to device serial number."; const char *verbose = "To print out verbose info."; const char *namespace_id = "Namespace to get logs from."; struct config cfg = { .namespace_id = NVME_NSID_ALL, - .file_prefix = NULL, + .dir_prefix = NULL, .type = NULL, }; OPT_ARGS(opts) = { OPT_STR("type", 't', &cfg.type, type), OPT_UINT("namespace-id", 'n', &cfg.namespace_id, namespace_id), - OPT_FILE("file-prefix", 'p', &cfg.file_prefix, prefix), + OPT_FILE("dir-prefix", 'p', &cfg.dir_prefix, prefix), OPT_FLAG("verbose", 'v', &cfg.verbose, verbose), OPT_END() }; @@ -533,12 +556,22 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, if (err) return err; - if (!cfg.file_prefix) { + if (!cfg.dir_prefix) { err = get_serial_number(sn_prefix, dev_fd(dev)); if (err) - goto out_dev; - cfg.file_prefix = sn_prefix; + return err; + cfg.dir_prefix = sn_prefix; + } + t = time(NULL); + tm = *localtime(&t); + snprintf(folder, sizeof(folder), "%s-%d%02d%02d%02d%02d%02d", cfg.dir_prefix, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); + if (mkdir(folder, 0777) != 0) { + perror("mkdir"); + return -errno; } + cfg.dir_prefix = folder; + output_path = folder; if (!cfg.type) cfg.type = "ALL"; @@ -547,8 +580,9 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, *p = toupper(*p); } - if (!strcmp(cfg.type, "ALL")) + if (!strcmp(cfg.type, "ALL")) { all = true; + } if (all || !strcmp(cfg.type, "ASSERT")) { err = dump_assert_logs(dev, cfg); if (err == 0) @@ -592,14 +626,32 @@ int solidigm_get_internal_log(int argc, char **argv, struct command *command, perror("Error retrieving Telemetry Host Initiated"); } + if (log_count > 0) { + int ret_cmd; + char cmd[ARG_MAX]; + char *where_err = cfg.verbose ? "" : ">/dev/null 2>&1"; + + snprintf(zip_name, sizeof(zip_name), "%s.zip", cfg.dir_prefix); + snprintf(cmd, sizeof(cmd), "cd \"%s\" && zip -r \"../%s\" ./* %s", cfg.dir_prefix, + zip_name, where_err); + printf("Compressing logs to %s\n", zip_name); + ret_cmd = system(cmd); + if (ret_cmd == -1) + perror(cmd); + else { + output_path = zip_name; + snprintf(cmd, sizeof(cmd), "rm -rf %s", cfg.dir_prefix); + printf("Removing %s\n", cfg.dir_prefix); + if (system(cmd) != 0) + perror("Failed removing logs folder"); + } + } + if (log_count == 0) { if (err > 0) nvme_show_status(err); } else if ((log_count > 1) || cfg.verbose) - printf("Total: %d log files with prefix: %s\n", log_count, cfg.file_prefix); -out_dev: - /* Redundant close() to make static code analysis happy */ - close(dev->direct.fd); - dev_close(dev); + printf("Total: %d log files in %s\n", log_count, output_path); + return err; } |