diff --git a/libnvme/src/meson.build b/libnvme/src/meson.build index 67ec00b6d3..a11007fe45 100644 --- a/libnvme/src/meson.build +++ b/libnvme/src/meson.build @@ -5,7 +5,9 @@ # # Authors: Martin Belanger # -sources = [] +sources = [ + 'nvme/log.c', +] if host_system == 'windows' sources += [ 'nvme/mem-win.c', @@ -19,7 +21,6 @@ else 'nvme/ioctl.c', 'nvme/lib.c', 'nvme/linux.c', - 'nvme/log.c', 'nvme/mem-linux.c', 'nvme/nvme-cmds.c', 'nvme/sysfs.c', diff --git a/libnvme/src/nvme/linux.c b/libnvme/src/nvme/linux.c index a585b98d27..57fc237f8a 100644 --- a/libnvme/src/nvme/linux.c +++ b/libnvme/src/nvme/linux.c @@ -1836,23 +1836,30 @@ static int uuid_from_dmi_entries(char *system_uuid) static int uuid_from_product_uuid(char *system_uuid) { __cleanup_file FILE *stream = NULL; - ssize_t nread; - __cleanup_free char *line = NULL; - size_t len = 0; stream = fopen(PATH_DMI_PROD_UUID, "re"); if (!stream) return -ENXIO; - system_uuid[0] = '\0'; - nread = getline(&line, &len, stream); - if (nread != NVME_UUID_LEN_STRING) - return -ENXIO; + system_uuid[0] = '\0'; /* The kernel is handling the byte swapping according DMTF * SMBIOS 3.0 Section 7.2.1 System UUID */ - memcpy(system_uuid, line, NVME_UUID_LEN_STRING - 1); + /* + * Expect exactly: + * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + */ + if (!fgets(system_uuid, NVME_UUID_LEN_STRING, stream)) + return -ENXIO; + + if (strlen(system_uuid) != NVME_UUID_LEN_STRING - 1) + return -ENXIO; + + if (system_uuid[8] != '-' || system_uuid[13] != '-' || + system_uuid[18] != '-' || system_uuid[23] != '-') + return -ENXIO; + system_uuid[NVME_UUID_LEN_STRING - 1] = '\0'; return 0; diff --git a/libnvme/src/nvme/log.c b/libnvme/src/nvme/log.c index 342c57ed45..7cd090b7aa 100644 --- a/libnvme/src/nvme/log.c +++ b/libnvme/src/nvme/log.c @@ -8,9 +8,11 @@ * This file implements basic logging functionality. */ +#include #include #include #include +#include #include #include @@ -25,6 +27,36 @@ #define LOG_CLOCK CLOCK_MONOTONIC #endif +static ssize_t write_all(int fd, const void *buf, size_t count) +{ + const char *p = buf; + size_t total = 0; + + while (total < count) { + ssize_t n = write(fd, p + total, count - total); + + if (n > 0) { + total += n; + continue; + } + + if (n < 0) { + if (errno == EINTR) + continue; + + if (errno == EAGAIN) + continue; + + return -1; + } + + errno = EIO; + return -1; + } + + return total; +} + void __attribute__((format(printf, 4, 5))) __libnvme_msg(struct libnvme_global_ctx *ctx, int level, const char *func, const char *format, ...) @@ -45,6 +77,7 @@ __libnvme_msg(struct libnvme_global_ctx *ctx, int level, }; __cleanup_free char *header = NULL; __cleanup_free char *message = NULL; + __cleanup_free char *log = NULL; int idx = 0; if (level > l->level) @@ -78,9 +111,12 @@ __libnvme_msg(struct libnvme_global_ctx *ctx, int level, message = NULL; va_end(ap); - dprintf(l->fd, "%s%s", - header ? header : "", - message ? message : ""); + if (asprintf(&log, "%s%s", header ? header : "", + message ? message : "") == -1) + return; + + if (write_all(l->fd, log, strlen(log)) < 0) + perror("failed to write log entry"); } __libnvme_public void libnvme_set_logging_level( diff --git a/nvme-models.c b/nvme-models.c index 4a94906deb..68fb6547a4 100644 --- a/nvme-models.c +++ b/nvme-models.c @@ -18,6 +18,8 @@ static char *_fmt3 = "/sys/class/nvme/nvme%d/device/vendor"; static char *_fmt4 = "/sys/class/nvme/nvme%d/device/device"; static char *_fmt5 = "/sys/class/nvme/nvme%d/device/class"; +#define LINE_BUF_SIZE 1024 + static char fmt1[78]; static char fmt2[78]; static char fmt3[78]; @@ -84,23 +86,23 @@ static void format_and_print(char *save) if (!class_mid) { if (device_final) - snprintf(save, 1024, "%s %s %s", + snprintf(save, LINE_BUF_SIZE, "%s %s %s", locate_info(device_top, false, false), locate_info(device_mid, false, false), locate_info(device_final, true, false)); else - snprintf(save, 1024, "%s %s", + snprintf(save, LINE_BUF_SIZE, "%s %s", locate_info(device_top, false, false), locate_info(device_mid, false, false)); } else { if (device_final) - snprintf(save, 1024, "%s: %s %s %s", + snprintf(save, LINE_BUF_SIZE, "%s: %s %s %s", locate_info(class_mid, false, true), locate_info(device_top, false, false), locate_info(device_mid, false, false), locate_info(device_final, true, false)); else - snprintf(save, 1024, "%s: %s %s", + snprintf(save, LINE_BUF_SIZE, "%s: %s %s", locate_info(class_mid, false, true), locate_info(device_top, false, false), locate_info(device_mid, false, false)); @@ -113,18 +115,18 @@ static void format_all(char *save, char *vendor, char *device) format_and_print(save); else if (device_top && !device_mid && class_mid) - snprintf(save, 1024, "%s: %s Device %s", + snprintf(save, LINE_BUF_SIZE, "%s: %s Device %s", locate_info(class_mid, false, true), locate_info(device_top, false, false), device); else if (!device_top && class_mid) - snprintf(save, 1024, "%s: Vendor %s Device %s", + snprintf(save, LINE_BUF_SIZE, "%s: Vendor %s Device %s", locate_info(class_mid, false, true), vendor, device); else - snprintf(save, 1024, "Unknown device"); + snprintf(save, LINE_BUF_SIZE, "Unknown device"); } static int is_final_match(char *line, char *search) @@ -179,61 +181,59 @@ static inline int is_class_info(char *line) return !memcmp(line, "# C class", 9); } -static void parse_vendor_device(char **line, FILE *file, +static void parse_vendor_device(char *line, FILE *file, char *device, char *subdev, char *subven) { bool device_single_found = false; - size_t amnt = 1024; - size_t found = 0; - char *newline; + size_t len; - while ((found = getline(line, &amnt, file)) != -1) { - newline = *line; - if (is_comment(newline)) + while (fgets(line, LINE_BUF_SIZE, file) != NULL) { + len = strlen(line); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + if (is_comment(line)) continue; - if (!is_tab(newline)) + if (!is_tab(line)) return; - newline[found - 1] = '\0'; - if (!device_single_found && is_mid_level_match(newline, device, false)) { + if (!device_single_found && is_mid_level_match(line, device, false)) { device_single_found = true; - device_mid = strdup(newline); + device_mid = strdup(line); continue; } - if (device_single_found && is_inner_sub_vendev(newline, subven, subdev)) { - device_final = strdup(newline); + if (device_single_found && is_inner_sub_vendev(line, subven, subdev)) { + device_final = strdup(line); break; } } } -static void pull_class_info(char **_newline, FILE *file, char *class) +static void pull_class_info(char *line, FILE *file, char *class) { - size_t amnt; - size_t size = 1024; bool top_found = false; bool mid_found = false; - char *newline; - - while ((amnt = getline(_newline, &size, file)) != -1) { - newline = *_newline; - newline[amnt - 1] = '\0'; - if (!top_found && is_top_level_match(newline, class, true)) { - class_top = strdup(newline); + size_t len; + + while (fgets(line, LINE_BUF_SIZE, file) != NULL) { + len = strlen(line); + if (len > 0 && line[len - 1] == '\n') + line[len - 1] = '\0'; + if (!top_found && is_top_level_match(line, class, true)) { + class_top = strdup(line); top_found = true; continue; } if (!mid_found && top_found && - is_mid_level_match(newline, &class[4], true)) { - class_mid = strdup(newline); + is_mid_level_match(line, &class[4], true)) { + class_mid = strdup(line); mid_found = true; continue; } if (top_found && mid_found && - is_final_match(newline, &class[6])) { - class_final = strdup(newline); + is_final_match(line, &class[6])) { + class_final = strdup(line); break; } } @@ -297,17 +297,17 @@ static FILE *open_pci_ids(void) return NULL; } -char *nvme_product_name(int id) +static char *__nvme_product_name(int id) { - char *line = NULL; - ssize_t amnt; + char readbuf[LINE_BUF_SIZE]; char vendor[7] = { 0 }; char device[7] = { 0 }; char sub_device[7] = { 0 }; char sub_vendor[7] = { 0 }; char class[13] = { 0 }; - size_t size = 1024; - char ret; + size_t len; + int ret = 0; + char *result; FILE *file = open_pci_ids(); if (!file) @@ -327,33 +327,57 @@ char *nvme_product_name(int id) if (ret) goto error0; - line = malloc(1024); - if (!line) { - fprintf(stderr, "malloc: %s\n", libnvme_strerror(errno)); - goto error0; - } - - while ((amnt = getline(&line, &size, file)) != -1) { - if (is_comment(line) && !is_class_info(line)) + while (fgets(readbuf, sizeof(readbuf), file) != NULL) { + len = strlen(readbuf); + if (len > 0 && readbuf[len - 1] == '\n') + readbuf[len - 1] = '\0'; + if (is_comment(readbuf) && !is_class_info(readbuf)) continue; - if (is_top_level_match(line, vendor, false)) { - line[amnt - 1] = '\0'; + if (is_top_level_match(readbuf, vendor, false)) { free(device_top); - device_top = strdup(line); - parse_vendor_device(&line, file, + device_top = strdup(readbuf); + parse_vendor_device(readbuf, file, device, sub_device, sub_vendor); } - if (is_class_info(line)) - pull_class_info(&line, file, class); + if (is_class_info(readbuf)) + pull_class_info(readbuf, file, class); } fclose(file); - format_all(line, vendor, device); + + result = malloc(LINE_BUF_SIZE); + if (!result) { + fprintf(stderr, "malloc: %s\n", libnvme_strerror(errno)); + free_all(); + return NULL; + } + format_all(result, vendor, device); free_all(); - return line; + return result; error0: fclose(file); error1: - return strdup("NULL"); + return NULL; +} + +char *nvme_product_name(const char *devname) +{ + const char *base; + int id; + + if (!devname) + return NULL; + + base = strrchr(devname, '/'); + if (base) { + if (!base[1]) + return NULL; + devname = base + 1; + } + + if (sscanf(devname, "nvme%d", &id) != 1) + return NULL; + + return __nvme_product_name(id); } diff --git a/nvme-models.h b/nvme-models.h index 2dcc164ccc..882d9ce446 100644 --- a/nvme-models.h +++ b/nvme-models.h @@ -2,6 +2,6 @@ #ifndef NVME_MODEL_H #define NVME_MODEL_H -char *nvme_product_name(int id); +char *nvme_product_name(const char *devname); #endif diff --git a/nvme-print-binary.c b/nvme-print-binary.c index 74b5008bf6..35402f164e 100644 --- a/nvme-print-binary.c +++ b/nvme-print-binary.c @@ -137,7 +137,7 @@ static void binary_id_ns_descs(void *data, unsigned nsid) d_raw((unsigned char *)data, 0x1000); } -static void binary_id_ctrl(struct nvme_id_ctrl *ctrl, +static void binary_id_ctrl(struct nvme_id_ctrl *ctrl, const char *product_name, void (*vendor_show)(__u8 *vs, struct json_object *root)) { d_raw((unsigned char *)ctrl, sizeof(*ctrl)); diff --git a/nvme-print-json.c b/nvme-print-json.c index 9dd45385d8..56fa7e76a7 100644 --- a/nvme-print-json.c +++ b/nvme-print-json.c @@ -349,8 +349,8 @@ static void json_nvme_id_ns(struct nvme_id_ns *ns, unsigned int nsid, json_print(r); } -void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, - void (*vs)(__u8 *vs, struct json_object *r)) +void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, const char *product_name, + void (*vs)(__u8 *vs, struct json_object *r)) { struct json_object *r = json_create_object(); struct json_object *psds = json_create_array(); @@ -368,6 +368,9 @@ void json_nvme_id_ctrl(struct nvme_id_ctrl *ctrl, snprintf(fr, sizeof(fr), "%-.*s", (int)sizeof(ctrl->fr), ctrl->fr); snprintf(subnqn, sizeof(subnqn), "%-.*s", (int)sizeof(ctrl->subnqn), ctrl->subnqn); + if (product_name) + obj_add_str(r, "product_name", product_name); + obj_add_int(r, "vid", le16_to_cpu(ctrl->vid)); obj_add_int(r, "ssvid", le16_to_cpu(ctrl->ssvid)); obj_add_str(r, "sn", sn); diff --git a/nvme-print-stdout.c b/nvme-print-stdout.c index 6273694391..305c0e7da3 100644 --- a/nvme-print-stdout.c +++ b/nvme-print-stdout.c @@ -3348,11 +3348,14 @@ static void stdout_id_ctrl_power(struct nvme_id_ctrl *ctrl) } } -static void stdout_id_ctrl(struct nvme_id_ctrl *ctrl, +static void stdout_id_ctrl(struct nvme_id_ctrl *ctrl, const char *product_name, void (*vendor_show)(__u8 *vs, struct json_object *root)) { bool human = stdout_print_ops.flags & VERBOSE, vs = stdout_print_ops.flags & VS; + if (human && product_name) + printf("%s\n\n", product_name); + printf("NVME Identify Controller:\n"); printf("vid : %#x\n", le16_to_cpu(ctrl->vid)); printf("ssvid : %#x\n", le16_to_cpu(ctrl->ssvid)); @@ -4370,36 +4373,36 @@ static void stdout_changed_ns_list_log(struct nvme_ns_list *log, const char *dev NVME_ID_NS_LIST_MAX); } -static void stdout_effects_log_human(FILE *stream, __u32 effect) +static void stdout_effects_log_human(__u32 effect) { const char *set = "+"; const char *clr = "-"; - fprintf(stream, " CSUPP+"); - fprintf(stream, " LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr); - fprintf(stream, " NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr); - fprintf(stream, " NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr); - fprintf(stream, " CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr); - fprintf(stream, " USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr); + printf(" CSUPP+"); + printf(" LBCC%s", (effect & NVME_CMD_EFFECTS_LBCC) ? set : clr); + printf(" NCC%s", (effect & NVME_CMD_EFFECTS_NCC) ? set : clr); + printf(" NIC%s", (effect & NVME_CMD_EFFECTS_NIC) ? set : clr); + printf(" CCC%s", (effect & NVME_CMD_EFFECTS_CCC) ? set : clr); + printf(" USS%s", (effect & NVME_CMD_EFFECTS_UUID_SEL) ? set : clr); if ((effect & NVME_CMD_EFFECTS_CSER_MASK) >> 14 == 0) - fprintf(stream, " No CSER defined\n"); + printf(" No CSER defined\n"); else if ((effect & NVME_CMD_EFFECTS_CSER_MASK) >> 14 == 1) - fprintf(stream, " No admin command for any namespace\n"); + printf(" No admin command for any namespace\n"); else - fprintf(stream, " Reserved CSER\n"); + printf(" Reserved CSER\n"); if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 0) - fprintf(stream, " No command restriction\n"); + printf(" No command restriction\n"); else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 1) - fprintf(stream, " No other command for same namespace\n"); + printf(" No other command for same namespace\n"); else if ((effect & NVME_CMD_EFFECTS_CSE_MASK) >> 16 == 2) - fprintf(stream, " No other command for any namespace\n"); + printf(" No other command for any namespace\n"); else - fprintf(stream, " Reserved CSE\n"); + printf(" Reserved CSE\n"); } -static void stdout_effects_entry(FILE *stream, int admin, int index, +static void stdout_effects_entry(int admin, int index, __le32 entry, unsigned int human) { __u32 effect; @@ -4409,12 +4412,12 @@ static void stdout_effects_entry(FILE *stream, int admin, int index, effect = le32_to_cpu(entry); if (effect & NVME_CMD_EFFECTS_CSUPP) { - fprintf(stream, format_string, index, nvme_cmd_to_string(admin, index), + printf(format_string, index, nvme_cmd_to_string(admin, index), effect); if (human) - stdout_effects_log_human(stream, effect); + stdout_effects_log_human(effect); else - fprintf(stream, "\n"); + printf("\n"); } } @@ -4422,32 +4425,28 @@ static void stdout_effects_log_segment(int admin, int a, int b, struct nvme_cmd_effects_log *effects, char *header, int human) { - FILE *stream; - char *stream_location; - size_t stream_size; - - stream = open_memstream(&stream_location, &stream_size); - if (!stream) { - perror("Failed to open stream"); - return; - } + bool printed_header = false; for (int i = a; i < b; i++) { - if (admin) - stdout_effects_entry(stream, admin, i, effects->acs[i], human); - else - stdout_effects_entry(stream, admin, i, effects->iocs[i], human); - } + __le32 entry; + __u32 effect; - fclose(stream); + entry = admin ? effects->acs[i] : effects->iocs[i]; + effect = le32_to_cpu(entry); - if (stream_size && header) { - printf("%s\n", header); - fwrite(stream_location, stream_size, 1, stdout); - printf("\n"); + if (!(effect & NVME_CMD_EFFECTS_CSUPP)) + continue; + + if (!printed_header && header) { + printf("%s\n", header); + printed_header = true; + } + + stdout_effects_entry(admin, i, entry, human); } - free(stream_location); + if (printed_header) + printf("\n"); } static void stdout_effects_log_page(enum nvme_csi csi, diff --git a/nvme-print.c b/nvme-print.c index 34dc9e0c55..7a839a00ae 100644 --- a/nvme-print.c +++ b/nvme-print.c @@ -611,10 +611,13 @@ void nvme_show_id_ns_descs(void *data, unsigned int nsid, nvme_print_flags_t fla nvme_print(id_ns_descs, flags, data, nsid); } -void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, nvme_print_flags_t flags, - void (*vendor_show)(__u8 *vs, struct json_object *root)) +void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, const char *devname, + nvme_print_flags_t flags, + void (*vendor_show)(__u8 *vs, struct json_object *root)) { - nvme_print(id_ctrl, flags, ctrl, vendor_show); + __cleanup_free char *product_name = nvme_product_name(devname); + + nvme_print(id_ctrl, flags, ctrl, product_name, vendor_show); } void nvme_show_id_ctrl_nvm(struct nvme_id_ctrl_nvm *ctrl_nvm, diff --git a/nvme-print.h b/nvme-print.h index fa84acdda8..ead2c9293d 100644 --- a/nvme-print.h +++ b/nvme-print.h @@ -59,7 +59,8 @@ struct print_ops { void (*fdp_usage_log)(struct nvme_fdp_ruhu_log *log, size_t len); void (*fid_supported_effects_log)(struct nvme_fid_supported_effects_log *fid_log, const char *devname); void (*fw_log)(struct nvme_firmware_slot *fw_log, const char *devname); - void (*id_ctrl)(struct nvme_id_ctrl *ctrl, void (*vs)(__u8 *vs, struct json_object *root)); + void (*id_ctrl)(struct nvme_id_ctrl *ctrl, const char *product_name, + void (*vs)(__u8 *vs, struct json_object *root)); void (*id_ctrl_nvm)(struct nvme_id_ctrl_nvm *ctrl_nvm); void (*id_domain_list)(struct nvme_id_domain_list *id_dom); void (*id_independent_id_ns)(struct nvme_id_independent_id_ns *ns, unsigned int nsid); @@ -183,8 +184,9 @@ void nvme_show_lba_status_info(__u64 result); void nvme_show_relatives(struct libnvme_global_ctx *ctx, const char *name, nvme_print_flags_t flags); void nvme_show_id_iocs(struct nvme_id_iocs *iocs, nvme_print_flags_t flags); -void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, nvme_print_flags_t flags, - void (*vendor_show)(__u8 *vs, struct json_object *root)); +void nvme_show_id_ctrl(struct nvme_id_ctrl *ctrl, const char *devname, + nvme_print_flags_t flags, void (*vendor_show)(__u8 *vs, + struct json_object *root)); void nvme_show_id_ctrl_rpmbs(__le32 ctrl_rpmbs, nvme_print_flags_t flags); void nvme_show_id_ns(struct nvme_id_ns *ns, unsigned int nsid, unsigned int lba_index, bool cap_only, nvme_print_flags_t flags); diff --git a/nvme.c b/nvme.c index fb641817bf..0687bf16ec 100644 --- a/nvme.c +++ b/nvme.c @@ -3668,7 +3668,7 @@ int __id_ctrl(int argc, char **argv, struct command *acmd, struct plugin *plugin return err; } - nvme_show_id_ctrl(ctrl, flags, vs); + nvme_show_id_ctrl(ctrl, libnvme_transport_handle_get_name(hdl), flags, vs); return err; } diff --git a/plugins/micron/micron-nvme.c b/plugins/micron/micron-nvme.c index 42c250d597..2c9ab9cb80 100644 --- a/plugins/micron/micron-nvme.c +++ b/plugins/micron/micron-nvme.c @@ -4491,7 +4491,8 @@ static int micron_id_ctrl(int argc, char **argv, struct command *acmd, return err; } - nvme_show_id_ctrl(&ctrl, flags, micron_id_ctrl_vs); + nvme_show_id_ctrl(&ctrl, libnvme_transport_handle_get_name(hdl), + flags, micron_id_ctrl_vs); return 0; }