diff options
Diffstat (limited to '')
-rw-r--r-- | util/argconfig.c | 326 | ||||
-rw-r--r-- | util/argconfig.h | 2 | ||||
-rw-r--r-- | util/base64.c | 5 | ||||
-rw-r--r-- | util/cleanup.h | 33 | ||||
-rw-r--r-- | util/json.h | 2 | ||||
-rw-r--r-- | util/logging.c | 14 | ||||
-rw-r--r-- | util/meson.build | 1 | ||||
-rw-r--r-- | util/types.h | 10 | ||||
-rw-r--r-- | util/utils.c | 305 | ||||
-rw-r--r-- | util/utils.h | 150 |
10 files changed, 588 insertions, 260 deletions
diff --git a/util/argconfig.c b/util/argconfig.c index 5ec3d6f..3460720 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -30,6 +30,7 @@ */ #include "argconfig.h" +#include "cleanup.h" #include "suffix.h" #include <errno.h> @@ -43,10 +44,12 @@ #include <stdbool.h> #include <locale.h> -static const char *append_usage_str = ""; +static bool is_null_or_empty(const char *s) +{ + return !s || !*s; +} -static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option, - int index); +static const char *append_usage_str = ""; void argconfig_append_usage(const char *str) { @@ -134,7 +137,7 @@ void argconfig_print_help(const char *program_desc, return; fprintf(stderr, "\n\033[1mOptions:\033[0m\n"); - for (; s && s->option; s++) + for (; s->option; s++) show_option(s); } @@ -144,23 +147,9 @@ static int argconfig_error(char *type, const char *opt, const char *arg) return -EINVAL; } -int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val) -{ - char *endptr; - unsigned long tmp = strtoul(str, &endptr, 0); - - if (errno || tmp >= 1 << 8 || str == endptr) - return argconfig_error("byte", opt, str); - - *val = tmp; - - return 0; -} - -static int argconfig_parse_type(struct argconfig_commandline_options *s, struct option *option, - int index) +static int argconfig_parse_type(struct argconfig_commandline_options *s) { - void *value = (void *)(char *)s->default_value; + void *value = s->default_value; char *endptr; int ret = 0; @@ -168,87 +157,67 @@ static int argconfig_parse_type(struct argconfig_commandline_options *s, struct switch (s->config_type) { case CFG_STRING: - *((char **)value) = optarg; - break; - case CFG_SIZE: - *((size_t *)value) = strtol(optarg, &endptr, 0); - if (errno || optarg == endptr) - ret = argconfig_error("integer", option[index].name, optarg); + *(char **)value = optarg; break; case CFG_INT: - *((int *)value) = strtol(optarg, &endptr, 0); + *(int *)value = strtol(optarg, &endptr, 0); if (errno || optarg == endptr) - ret = argconfig_error("integer", option[index].name, optarg); + ret = argconfig_error("integer", s->option, optarg); break; - case CFG_BYTE: - ret = argconfig_parse_byte(option[index].name, optarg, (uint8_t *)value); + case CFG_BYTE: { + unsigned long tmp = strtoul(optarg, &endptr, 0); + + if (errno || tmp >= 1 << 8 || optarg == endptr) + ret = argconfig_error("byte", s->option, optarg); + else + *(uint8_t *)value = tmp; break; + } case CFG_SHORT: { unsigned long tmp = strtoul(optarg, &endptr, 0); if (errno || tmp >= 1 << 16 || optarg == endptr) - ret = argconfig_error("short", option[index].name, optarg); + ret = argconfig_error("short", s->option, optarg); else - *((uint16_t *)value) = tmp; + *(uint16_t *)value = tmp; break; } case CFG_POSITIVE: { uint32_t tmp = strtoul(optarg, &endptr, 0); if (errno || optarg == endptr) - ret = argconfig_error("word", option[index].name, optarg); + ret = argconfig_error("word", s->option, optarg); else - *((uint32_t *)value) = tmp; + *(uint32_t *)value = tmp; break; } case CFG_INCREMENT: - *((int *)value) += 1; + *(int *)value += 1; break; case CFG_LONG: - *((unsigned long *)value) = strtoul(optarg, &endptr, 0); + *(unsigned long *)value = strtoul(optarg, &endptr, 0); if (errno || optarg == endptr) - ret = argconfig_error("long integer", option[index].name, optarg); + ret = argconfig_error("long integer", s->option, optarg); break; case CFG_LONG_SUFFIX: ret = suffix_binary_parse(optarg, &endptr, (uint64_t *)value); if (ret) - argconfig_error("long suffixed integer", option[index].name, optarg); + argconfig_error("long suffixed integer", s->option, optarg); break; case CFG_DOUBLE: - *((double *)value) = strtod(optarg, &endptr); + *(double *)value = strtod(optarg, &endptr); if (errno || optarg == endptr) - ret = argconfig_error("float", option[index].name, optarg); + ret = argconfig_error("float", s->option, optarg); break; case CFG_FLAG: - *((bool *)value) = true; - break; - default: + *(bool *)value = true; break; } return ret; } -static int argconfig_get_val_len(struct argconfig_opt_val *opt_val, const char *str) -{ - struct argconfig_opt_val *v; - int len; - int match; - - for (len = 1; len <= strlen(str); len++) { - match = 0; - for (v = opt_val; v && v->str; v++) { - if (!strncasecmp(str, v->str, len)) - match++; - } - if (match == 1) - break; - } - - return len; -} - -static int argconfig_set_opt_val(enum argconfig_types type, union argconfig_val *opt_val, void *val) +static void argconfig_set_opt_val(enum argconfig_types type, union argconfig_val *opt_val, void *val) { switch (type) { case CFG_FLAG: @@ -281,30 +250,39 @@ static int argconfig_set_opt_val(enum argconfig_types type, union argconfig_val case CFG_STRING: *(char **)val = opt_val->string; break; - default: - break; } - - return 0; } -static int argconfig_parse_val(struct argconfig_commandline_options *s, struct option *option, - int index) +static struct argconfig_opt_val * +argconfig_match_val(struct argconfig_opt_val *v, const char *str) { - const char *str = optarg; - void *val = s->default_value; - int len = strlen(optarg); - struct argconfig_opt_val *v; - int val_len; - - for (v = s->opt_val; v && v->str; v++) { - val_len = argconfig_get_val_len(s->opt_val, v->str); - if (strncasecmp(str, v->str, len > val_len ? len : val_len)) + size_t len = strlen(str); + struct argconfig_opt_val *match = NULL; + + for (; v->str; v++) { + if (strncasecmp(str, v->str, len)) continue; - return argconfig_set_opt_val(v->type, &v->val, val); + + if (match) + return NULL; /* multiple matches; input is ambiguous */ + + match = v; } - return argconfig_parse_type(s, option, index); + return match; +} + +static int argconfig_parse_val(struct argconfig_commandline_options *s) +{ + struct argconfig_opt_val *v = s->opt_val; + + if (v) + v = argconfig_match_val(v, optarg); + if (!v) + return argconfig_parse_type(s); + + argconfig_set_opt_val(v->type, &v->val, s->default_value); + return 0; } static bool argconfig_check_human_readable(struct argconfig_commandline_options *s) @@ -320,8 +298,8 @@ static bool argconfig_check_human_readable(struct argconfig_commandline_options int argconfig_parse(int argc, char *argv[], const char *program_desc, struct argconfig_commandline_options *options) { - char *short_opts; - struct option *long_opts; + _cleanup_free_ char *short_opts = NULL; + _cleanup_free_ struct option *long_opts = NULL; struct argconfig_commandline_options *s; int c, option_index = 0, short_index = 0, options_count = 0; int ret = 0; @@ -330,16 +308,15 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, for (s = options; s->option; s++) options_count++; - long_opts = calloc(1, sizeof(struct option) * (options_count + 3)); - short_opts = calloc(1, sizeof(*short_opts) * (options_count * 3 + 5)); + long_opts = calloc(options_count + 2, sizeof(struct option)); + short_opts = calloc(options_count * 3 + 3, sizeof(*short_opts)); if (!long_opts || !short_opts) { fprintf(stderr, "failed to allocate memory for opts: %s\n", strerror(errno)); - ret = -errno; - goto out; + return -errno; } - for (s = options; s->option && option_index < options_count; s++) { + for (s = options; s->option; s++) { if (s->short_option) { short_opts[short_index++] = s->short_option; if (s->argument_type == required_argument || @@ -348,7 +325,7 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (s->argument_type == optional_argument) short_opts[short_index++] = ':'; } - if (s->option && strlen(s->option)) { + if (!is_null_or_empty(s->option)) { long_opts[option_index].name = s->option; long_opts[option_index].has_arg = s->argument_type; } @@ -384,10 +361,7 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (!s->default_value) continue; - if (s->opt_val) - ret = argconfig_parse_val(s, long_opts, option_index); - else - ret = argconfig_parse_type(s, long_opts, option_index); + ret = argconfig_parse_val(s); if (ret) break; } @@ -395,139 +369,12 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, if (!argconfig_check_human_readable(options)) setlocale(LC_ALL, "C"); -out: - free(short_opts); - free(long_opts); return ret; } -int argconfig_parse_comma_sep_array(char *string, int *val, unsigned int max_length) -{ - int ret = 0; - unsigned long v; - char *tmp; - char *p; - - if (!string || !strlen(string)) - return 0; - - tmp = strtok(string, ","); - if (!tmp) - return 0; - - v = strtoul(tmp, &p, 0); - if (*p != 0) - return -1; - if (v > UINT_MAX) { - fprintf(stderr, "%s out of range\n", tmp); - return -1; - } - val[ret] = v; - - ret++; - while (1) { - tmp = strtok(NULL, ","); - - if (tmp == NULL) - return ret; - - if (ret >= max_length) - return -1; - - v = strtoul(tmp, &p, 0); - if (*p != 0) - return -1; - if (v > UINT_MAX) { - fprintf(stderr, "%s out of range\n", tmp); - return -1; - } - val[ret] = v; - ret++; - } -} - -int argconfig_parse_comma_sep_array_short(char *string, unsigned short *val, - unsigned int max_length) -{ - int ret = 0; - unsigned long v; - char *tmp; - char *p; - - if (!string || !strlen(string)) - return 0; - - tmp = strtok(string, ","); - if (!tmp) - return 0; - - v = strtoul(tmp, &p, 0); - if (*p != 0) - return -1; - if (v > UINT16_MAX) { - fprintf(stderr, "%s out of range\n", tmp); - return -1; - } - val[ret] = v; - ret++; - - while (1) { - tmp = strtok(NULL, ","); - if (tmp == NULL) - return ret; - - if (ret >= max_length) - return -1; - - v = strtoul(tmp, &p, 0); - if (*p != 0) - return -1; - if (v > UINT16_MAX) { - fprintf(stderr, "%s out of range\n", tmp); - return -1; - } - val[ret] = v; - ret++; - } -} - -int argconfig_parse_comma_sep_array_long(char *string, unsigned long long *val, - unsigned int max_length) -{ - int ret = 0; - char *tmp; - char *p; - - if (!string || !strlen(string)) - return 0; - - tmp = strtok(string, ","); - if (tmp == NULL) - return 0; - - val[ret] = strtoll(tmp, &p, 0); - if (*p != 0) - return -1; - ret++; - while (1) { - tmp = strtok(NULL, ","); - - if (tmp == NULL) - return ret; - - if (ret >= max_length) - return -1; - - val[ret] = strtoll(tmp, &p, 0); - if (*p != 0) - return -1; - ret++; - } -} - -#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(size) \ -int argconfig_parse_comma_sep_array_u##size(char *string, \ - __u##size *val, \ +#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(name, ret_t, ret_max) \ +int argconfig_parse_comma_sep_array ## name(char *string, \ + ret_t *val, \ unsigned int max_length) \ { \ int ret = 0; \ @@ -535,44 +382,39 @@ int argconfig_parse_comma_sep_array_u##size(char *string, \ char *tmp; \ char *p; \ \ - if (!string || !strlen(string)) \ + if (is_null_or_empty(string)) \ return 0; \ \ tmp = strtok(string, ","); \ - if (!tmp) \ - return 0; \ - \ - v = strtoumax(tmp, &p, 0); \ - if (*p != 0) \ - return -1; \ - if (v > UINT##size##_MAX) { \ - fprintf(stderr, "%s out of range\n", tmp); \ - return -1; \ - } \ - val[ret] = v; \ - \ - ret++; \ - while (1) { \ - tmp = strtok(NULL, ","); \ - \ - if (tmp == NULL) \ - return ret; \ \ + while (tmp) { \ if (ret >= max_length) \ return -1; \ \ v = strtoumax(tmp, &p, 0); \ if (*p != 0) \ return -1; \ - if (v > UINT##size##_MAX) { \ + if (v > ret_max) { \ fprintf(stderr, "%s out of range\n", tmp); \ return -1; \ } \ val[ret] = v; \ ret++; \ + \ + tmp = strtok(NULL, ","); \ } \ + \ + return ret; \ } +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(, int, UINT_MAX) +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_short, unsigned short, UINT16_MAX) +DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_long, unsigned long long, ULLONG_MAX) + +#define DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(size) \ + DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_FUNC(_u ## size, __u ## size, \ + UINT ## size ## _MAX) + DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(16); DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(32); DEFINE_ARGCONFIG_PARSE_COMMA_SEP_ARRAY_UINT_FUNC(64); diff --git a/util/argconfig.h b/util/argconfig.h index 2a04a32..3dff25a 100644 --- a/util/argconfig.h +++ b/util/argconfig.h @@ -47,7 +47,6 @@ enum argconfig_types { CFG_FLAG, CFG_STRING, CFG_INT, - CFG_SIZE, CFG_LONG, CFG_LONG_SUFFIX, CFG_DOUBLE, @@ -181,7 +180,6 @@ int argconfig_parse_comma_sep_array_u32(char *string, __u32 *val, unsigned int max_length); int argconfig_parse_comma_sep_array_u64(char *string, __u64 *val, unsigned int max_length); -int argconfig_parse_byte(const char *opt, const char *str, unsigned char *val); void print_word_wrapped(const char *s, int indent, int start, FILE *stream); bool argconfig_parse_seen(struct argconfig_commandline_options *options, diff --git a/util/base64.c b/util/base64.c index 7f47cda..0e89f2e 100644 --- a/util/base64.c +++ b/util/base64.c @@ -20,6 +20,7 @@ * MA 02110-1301, USA. */ +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <errno.h> @@ -42,7 +43,7 @@ static const char base64_table[65] = int base64_encode(const unsigned char *src, int srclen, char *dst) { int i, bits = 0; - u_int32_t ac = 0; + uint32_t ac = 0; char *cp = dst; for (i = 0; i < srclen; i++) { @@ -77,7 +78,7 @@ int base64_encode(const unsigned char *src, int srclen, char *dst) */ int base64_decode(const char *src, int srclen, unsigned char *dst) { - u_int32_t ac = 0; + uint32_t ac = 0; int i, bits = 0; unsigned char *bp = dst; diff --git a/util/cleanup.h b/util/cleanup.h index ee9b120..ff26cda 100644 --- a/util/cleanup.h +++ b/util/cleanup.h @@ -5,6 +5,8 @@ #include <unistd.h> #include <stdlib.h> +#include <libnvme.h> + #include "util/mem.h" #define __cleanup__(fn) __attribute__((cleanup(fn))) @@ -21,17 +23,36 @@ DECLARE_CLEANUP_FUNC(name, type) \ static inline void freep(void *p) { - free(*(void**) p); + free(*(void **)p); } #define _cleanup_free_ __cleanup__(freep) #define _cleanup_huge_ __cleanup__(nvme_free_huge) -static inline void close_file(int *f) +static inline void cleanup_fd(int *fd) { - if (*f > STDERR_FILENO) - close(*f); + if (*fd > STDERR_FILENO) + close(*fd); } -#define _cleanup_file_ __cleanup__(close_file) +#define _cleanup_fd_ __cleanup__(cleanup_fd) + +static inline void cleanup_nvme_root(nvme_root_t *r) +{ + nvme_free_tree(*r); +} +#define _cleanup_nvme_root_ __cleanup__(cleanup_nvme_root) + +static inline DEFINE_CLEANUP_FUNC(cleanup_nvme_ctrl, nvme_ctrl_t, nvme_free_ctrl) +#define _cleanup_nvme_ctrl_ __cleanup__(cleanup_nvme_ctrl) + +static inline void free_uri(struct nvme_fabrics_uri **uri) +{ + if (*uri) + nvme_free_uri(*uri); +} +#define _cleanup_uri_ __cleanup__(free_uri) + +static inline DEFINE_CLEANUP_FUNC(cleanup_file, FILE *, fclose) +#define _cleanup_file_ __cleanup__(cleanup_file) -#endif +#endif /* __CLEANUP_H */ diff --git a/util/json.h b/util/json.h index 54e33e3..3dd5b52 100644 --- a/util/json.h +++ b/util/json.h @@ -56,6 +56,8 @@ uint64_t util_json_object_get_uint64(struct json_object *obj); struct json_object; +#define json_object_add_value_string(o, k, v) + #endif #endif diff --git a/util/logging.c b/util/logging.c index c26d9e2..8e59948 100644 --- a/util/logging.c +++ b/util/logging.c @@ -92,15 +92,14 @@ int nvme_submit_passthru(int fd, unsigned long ioctl_cmd, struct timeval end; int err; - if (log_level >= LOG_INFO) + if (log_level >= LOG_DEBUG) gettimeofday(&start, NULL); err = ioctl(fd, ioctl_cmd, cmd); - if (log_level >= LOG_INFO) { + if (log_level >= LOG_DEBUG) { gettimeofday(&end, NULL); - if (log_level >= LOG_DEBUG) - nvme_show_command(cmd, err); + nvme_show_command(cmd, err); nvme_show_latency(start, end); } @@ -118,16 +117,15 @@ int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd, struct timeval end; int err; - if (log_level >= LOG_INFO) + if (log_level >= LOG_DEBUG) gettimeofday(&start, NULL); err = ioctl(fd, ioctl_cmd, cmd); - if (log_level >= LOG_INFO) { + if (log_level >= LOG_DEBUG) { gettimeofday(&end, NULL); - if (log_level >= LOG_DEBUG) - nvme_show_command64(cmd, err); + nvme_show_command64(cmd, err); nvme_show_latency(start, end); } diff --git a/util/meson.build b/util/meson.build index 0065b86..f5474cd 100644 --- a/util/meson.build +++ b/util/meson.build @@ -8,6 +8,7 @@ sources += [ 'util/mem.c', 'util/suffix.c', 'util/types.c', + 'util/utils.c' ] if json_c_dep.found() diff --git a/util/types.h b/util/types.h index 595958b..9e0806c 100644 --- a/util/types.h +++ b/util/types.h @@ -16,6 +16,16 @@ static inline long kelvin_to_celsius(long t) return t + ABSOLUTE_ZERO_CELSIUS; } +static inline long celsius_to_fahrenheit(long t) +{ + return t * 9 / 5 + 32; +} + +static inline long kelvin_to_fahrenheit(long t) +{ + return celsius_to_fahrenheit(kelvin_to_celsius(t)); +} + /* uint128_t is not always available, define our own. */ union nvme_uint128 { __u8 bytes[16]; diff --git a/util/utils.c b/util/utils.c new file mode 100644 index 0000000..5d77652 --- /dev/null +++ b/util/utils.c @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Micron, Inc 2024. + * + * @file: micron-utils.h + * @brief: This module contains all the utilities needed for other modules. + * @author: Chaithanya Shoba <ashoba@micron.com> + */ + +#include "utils.h" +#include "types.h" +#include "json.h" + +int hex_to_int(char c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return 10 + (c - 'A'); + else if (c >= 'a' && c <= 'f') + return 10 + (c - 'a'); + else + return -1; // Invalid character +} + +char *hex_to_ascii(const char *hex) +{ + int hex_length = strlen(hex); + + char *text = NULL; + + if (hex_length > 0) { + int symbol_count; + int odd_hex_count = hex_length % 2 == 1; + + if (odd_hex_count) + symbol_count = (hex_length / 2) + 1; + else + symbol_count = hex_length / 2; + + text = (char *)malloc(symbol_count + 1); // Allocate memory for the result + + int last_index = hex_length - 1; + + for (int i = last_index; i >= 0; --i) { + if ((last_index - i) % 2 != 0) { + int dec = 16 * hex_to_int(hex[i]) + hex_to_int(hex[i + 1]); + + if (odd_hex_count) + text[i / 2 + 1] = dec; + else + text[i / 2] = dec; + } else if (i == 0) { + int dec = hex_to_int(hex[0]); + + text[0] = dec; + } + } + + text[symbol_count] = '\0'; // Terminate the string + } + + return text; +} + +unsigned char *read_binary_file(char *data_dir_path, const char *bin_path, + long *buffer_size, int retry_count) +{ + char *file_path = NULL; + FILE *bin_file = NULL; + size_t n_data = 0; + unsigned char *buffer = NULL; + + /* set path */ + if (data_dir_path == NULL) { + file_path = (char *)bin_path; + } else { + /* +2 for the / and null terminator */ + file_path = (char *) calloc(1, strlen(data_dir_path) + strlen(bin_path) + 2); + if (!file_path) + return NULL; + + if (strlen(bin_path) != 0) + sprintf(file_path, "%s/%s", data_dir_path, bin_path); + else + sprintf(file_path, "%s", data_dir_path); + } + + /* open file */ + for (int i = 0; i < retry_count; i++) { + bin_file = fopen(file_path, "rb"); + if (bin_file != NULL) + break; + sleep((unsigned int)(retry_count > 1)); + } + + if (!bin_file) { + nvme_show_error("\nFailed to open %s", file_path); + if (file_path != bin_path) + free(file_path); + return NULL; + } + + /* get size */ + fseek(bin_file, 0, SEEK_END); + *buffer_size = ftell(bin_file); + fseek(bin_file, 0, SEEK_SET); + if (*buffer_size <= 0) { + fclose(bin_file); + return NULL; + } + + /* allocate buffer */ + buffer = (unsigned char *)malloc(*buffer_size); + if (!buffer) { + nvme_show_result("\nFailed to allocate %ld bytes!", *buffer_size); + fclose(bin_file); + return NULL; + } + memset(buffer, 0, *buffer_size); + + /* Read data */ + n_data = fread(buffer, 1, *buffer_size, bin_file); + + /* Close file */ + fclose(bin_file); + + /* Validate we read data */ + if (n_data != (size_t)*buffer_size) { + nvme_show_result("\nFailed to read %ld bytes from %s", *buffer_size, file_path); + return NULL; + } + + if (file_path != bin_path) + free(file_path); + return buffer; +} + +void print_formatted_var_size_str(const char *msg, const __u8 *pdata, size_t data_size, FILE *fp) +{ + char description_str[256] = ""; + char temp_buffer[3] = { 0 }; + + for (size_t i = 0; i < data_size; ++i) { + sprintf(temp_buffer, "%02X", pdata[i]); + strcat(description_str, temp_buffer); + } + + if (fp) + fprintf(fp, "%s: %s\n", msg, description_str); + else + printf("%s: %s\n", msg, description_str); +} + +void process_field_size_16(int offset, char *sfield, __u8 *buf, char *datastr) +{ + __u64 lval_lo, lval_hi; + + if (strstr(sfield, "GUID")) { + sprintf(datastr, "0x%"PRIx64"%"PRIx64"", + le64_to_cpu(*(__u64 *)(&buf[offset + 8])), + le64_to_cpu(*(__u64 *)(&buf[offset]))); + } else { + lval_lo = *((__u64 *)(&buf[offset])); + lval_hi = *((__u64 *)(&buf[offset + 8])); + + if (lval_hi) + sprintf(datastr, "0x%"PRIx64"%016"PRIx64"", + le64_to_cpu(lval_hi), le64_to_cpu(lval_lo)); + else + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } +} + +void process_field_size_8(int offset, char *sfield, __u8 *buf, char *datastr) +{ + __u64 lval_lo; + + if (strstr(sfield, "Boot SSD Spec Version")) { + sprintf(datastr, "%x.%x.%x.%x", + le16_to_cpu(*((__u16 *)(&buf[300]))), + le16_to_cpu(*((__u16 *)(&buf[302]))), + le16_to_cpu(*((__u16 *)(&buf[304]))), + le16_to_cpu(*((__u16 *)(&buf[306])))); + } else if (strstr(sfield, "Firmware Revision")) { + char buffer[30] = {'\0'}; + + lval_lo = *((__u64 *)(&buf[offset])); + + sprintf(buffer, "%"PRIx64, __builtin_bswap64(lval_lo)); + sprintf(datastr, "%s", hex_to_ascii(buffer)); + } else if (strstr(sfield, "Timestamp")) { + char ts_buf[128]; + + lval_lo = *((__u64 *)(&buf[offset])); + + convert_ts(le64_to_cpu(lval_lo), ts_buf); + sprintf(datastr, "%s", ts_buf); + } else { + lval_lo = *((__u64 *)(&buf[offset])); + + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } +} + +void process_field_size_7(int offset, char *sfield, __u8 *buf, char *datastr) +{ + __u8 lval[8] = { 0 }; + __u64 lval_lo; + + /* 7 bytes will be in little-endian format, with last byte as MSB */ + memcpy(&lval[0], &buf[offset], 7); + memcpy((void *)&lval_lo, lval, 8); + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); +} + +void process_field_size_6(int offset, char *sfield, __u8 *buf, char *datastr) +{ + __u32 ival; + __u16 sval; + __u64 lval_lo; + + if (strstr(sfield, "DSSD Spec Version")) { + sprintf(datastr, "%x.%x.%x.%x", buf[103], + le16_to_cpu(*((__u16 *)(&buf[101]))), + le16_to_cpu(*((__u16 *)(&buf[99]))), buf[98]); + } else { + ival = *((__u32 *)(&buf[offset])); + sval = *((__u16 *)(&buf[offset + 4])); + lval_lo = (((__u64)sval << 32) | ival); + + sprintf(datastr, "0x%"PRIx64"", le64_to_cpu(lval_lo)); + } +} + +void process_field_size_default(int offset, char *sfield, __u8 *buf, int size, char *datastr) +{ + __u8 cval; + char description_str[256] = "0x"; + char temp_buffer[3] = { 0 }; + + for (unsigned char i = 0; i < (unsigned char)size; i++) { + cval = (buf[offset + i]); + + sprintf(temp_buffer, "%02X", cval); + strcat(description_str, temp_buffer); + } + sprintf(datastr, "%s", description_str); +} + +void generic_structure_parser(__u8 *buf, struct request_data *req_data, int field_count, + struct json_object *stats, __u8 spec, FILE *fp) +{ + int offset = 0; + + for (int field = 0; field < field_count; field++) { + char datastr[1024] = { 0 }; + char *sfield = req_data[field].field; + int size = !spec ? req_data[field].size : req_data[field].size2; + + if (!size || sfield == NULL) + continue; + + switch (size) { + case FIELD_SIZE_16: + process_field_size_16(offset, sfield, buf, datastr); + break; + case FIELD_SIZE_8: + process_field_size_8(offset, sfield, buf, datastr); + break; + case FIELD_SIZE_7: + process_field_size_7(offset, sfield, buf, datastr); + break; + case FIELD_SIZE_6: + process_field_size_6(offset, sfield, buf, datastr); + break; + case FIELD_SIZE_4: + sprintf(datastr, "0x%x", le32_to_cpu(*((__u32 *)(&buf[offset])))); + break; + case FIELD_SIZE_3: + sprintf(datastr, "0x%02X%02X%02X", + buf[offset + 0], buf[offset + 1], buf[offset + 2]); + break; + case FIELD_SIZE_2: + sprintf(datastr, "0x%04x", le16_to_cpu(*((__u16 *)(&buf[offset])))); + break; + case FIELD_SIZE_1: + sprintf(datastr, "0x%02x", buf[offset]); + break; + default: + process_field_size_default(offset, sfield, buf, size, datastr); + break; + } + offset += size; + /* do not print reserved values */ + if (strstr(sfield, "Reserved")) + continue; + if (stats) + json_object_add_value_string(stats, sfield, datastr); + else if (fp) + fprintf(fp, "%-40s : %-4s\n", sfield, datastr); + else + printf("%-40s : %-4s\n", sfield, datastr); + } +} diff --git a/util/utils.h b/util/utils.h new file mode 100644 index 0000000..35ba550 --- /dev/null +++ b/util/utils.h @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Micron, Inc 2024. + * + * @file: utils.h + * @brief: This module contains all the utilities needed for other modules. + * @author: Chaithanya Shoba <ashoba@micron.com> + */ + +#include "common.h" +#include "nvme-print.h" + +/*Request data format*/ +struct __packed request_data { + char *field; + int size; + int size2; +}; + +enum field_size { + FIELD_SIZE_16 = 16, + FIELD_SIZE_8 = 8, + FIELD_SIZE_7 = 7, + FIELD_SIZE_6 = 6, + FIELD_SIZE_4 = 4, + FIELD_SIZE_3 = 3, + FIELD_SIZE_2 = 2, + FIELD_SIZE_1 = 1 +}; + +/** + * @brief converts a single hexadecimal character to its integer value. + * + * @param hex_char, input hex char + * @param ts_buf, output time string + * + * @return integer value of hexadecimal + */ +int hex_to_int(char c); + +/** + * @brief convert time_t format time to a human readable string + * + * @param hex_string, input hex string pointer + * @param ascii_buffer, output ascii buffer pointer + * + * @return nothing + */ +char *hex_to_ascii(const char *hex); + +/** + * @brief convert time_t format time to a human readable string + * + * @param data_dir_path, input data directory path pointer + * @param bin_path, input binary file path pointer + * @param buffer_size, input buffer size pointer + * @param retry_count, input retry count + * + * @return pointer to binary data buffer + */ +unsigned char *read_binary_file(char *data_dir_path, const char *bin_path, long *buffer_size, + int retry_count); + +/** + * @brief prints generic structure parser + * + * @param buf, input raw log data + * @param log_page, input format of the data + * @param field_count, intput log field count + * @param stats, input json object to add fields + * @param spec, input ocp spec index + * @param fp, input file pointer + * + * @return 0 success + */ +void generic_structure_parser(__u8 *buf, struct request_data *req_data, int field_count, + struct json_object *stats, __u8 spec, FILE *fp); + +/** + * @brief prints raw data to the buffer + * + * @param msg, intput buffer to write data + * @param pdata, input raw data + * @param data_size, input size of the data + * @param fp, input file pointer + * + * @return 0 success + */ +void print_formatted_var_size_str(const char *msg, const __u8 *pdata, size_t data_size, FILE *fp); + +/** + * @brief prints raw data to the buffer + * + * @param offset, intput offset of the param + * @param sfield, intput field + * @param buf, input raw data + * @param datastr, output data buffer + * + * @return 0 success + */ +void process_field_size_16(int offset, char *sfield, __u8 *buf, char *datastr); + +/** + * @brief prints raw data to the buffer + * + * @param offset, intput offset of the param + * @param sfield, intput field + * @param buf, input raw data + * @param datastr, output data buffer + * + * @return 0 success + */ +void process_field_size_8(int offset, char *sfield, __u8 *buf, char *datastr); + +/** + * @brief prints raw data to the buffer + * + * @param offset, intput offset of the param + * @param sfield, intput field + * @param buf, input raw data + * @param datastr, output data buffer + * + * @return 0 success + */ +void process_field_size_7(int offset, char *sfield, __u8 *buf, char *datastr); + +/** + * @brief prints raw data to the buffer + * + * @param offset, intput offset of the param + * @param sfield, intput field + * @param buf, input raw data + * @param datastr, output data buffer + * + * @return 0 success + */ +void process_field_size_6(int offset, char *sfield, __u8 *buf, char *datastr); + +/** + * @brief prints raw data to the buffer + * + * @param offset, intput offset of the param + * @param sfield, intput field + * @param buf, input raw data + * @param size, input data size + * @param datastr, output data buffer + * + * @return 0 success + */ +void process_field_size_default(int offset, char *sfield, __u8 *buf, int size, char *datastr); |