summaryrefslogtreecommitdiffstats
path: root/util
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--util/argconfig.c326
-rw-r--r--util/argconfig.h2
-rw-r--r--util/base64.c5
-rw-r--r--util/cleanup.h33
-rw-r--r--util/json.h2
-rw-r--r--util/logging.c136
-rw-r--r--util/logging.h12
-rw-r--r--util/meson.build2
-rw-r--r--util/types.h10
-rw-r--r--util/utils.c305
-rw-r--r--util/utils.h150
11 files changed, 731 insertions, 252 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
new file mode 100644
index 0000000..8e59948
--- /dev/null
+++ b/util/logging.c
@@ -0,0 +1,136 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <inttypes.h>
+
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/syslog.h>
+#include <sys/time.h>
+#include <linux/types.h>
+
+#include <libnvme.h>
+
+#include "logging.h"
+
+int log_level;
+
+int map_log_level(int verbose, bool quiet)
+{
+ int log_level;
+
+ /*
+ * LOG_NOTICE is unused thus the user has to provide two 'v' for getting
+ * any feedback at all. Thus skip this level
+ */
+ verbose++;
+
+ switch (verbose) {
+ case 0:
+ log_level = LOG_WARNING;
+ break;
+ case 1:
+ log_level = LOG_NOTICE;
+ break;
+ case 2:
+ log_level = LOG_INFO;
+ break;
+ default:
+ log_level = LOG_DEBUG;
+ break;
+ }
+ if (quiet)
+ log_level = LOG_ERR;
+
+ return log_level;
+}
+
+static void nvme_show_common(struct nvme_passthru_cmd *cmd)
+{
+ printf("opcode : %02x\n", cmd->opcode);
+ printf("flags : %02x\n", cmd->flags);
+ printf("rsvd1 : %04x\n", cmd->rsvd1);
+ printf("nsid : %08x\n", cmd->nsid);
+ printf("cdw2 : %08x\n", cmd->cdw2);
+ printf("cdw3 : %08x\n", cmd->cdw3);
+ printf("data_len : %08x\n", cmd->data_len);
+ printf("metadata_len : %08x\n", cmd->metadata_len);
+ printf("addr : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->addr);
+ printf("metadata : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->metadata);
+ printf("cdw10 : %08x\n", cmd->cdw10);
+ printf("cdw11 : %08x\n", cmd->cdw11);
+ printf("cdw12 : %08x\n", cmd->cdw12);
+ printf("cdw13 : %08x\n", cmd->cdw13);
+ printf("cdw14 : %08x\n", cmd->cdw14);
+ printf("cdw15 : %08x\n", cmd->cdw15);
+ printf("timeout_ms : %08x\n", cmd->timeout_ms);
+}
+
+static void nvme_show_command(struct nvme_passthru_cmd *cmd, int err)
+{
+ nvme_show_common(cmd);
+ printf("result : %08x\n", cmd->result);
+ printf("err : %d\n", err);
+}
+
+static void nvme_show_command64(struct nvme_passthru_cmd64 *cmd, int err)
+{
+ nvme_show_common((struct nvme_passthru_cmd *)cmd);
+ printf("result : %"PRIx64"\n", (uint64_t)(uintptr_t)cmd->result);
+ printf("err : %d\n", err);
+}
+
+static void nvme_show_latency(struct timeval start, struct timeval end)
+{
+ printf("latency : %lu us\n",
+ (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec));
+}
+
+int nvme_submit_passthru(int fd, unsigned long ioctl_cmd,
+ struct nvme_passthru_cmd *cmd, __u32 *result)
+{
+ struct timeval start;
+ struct timeval end;
+ int err;
+
+ if (log_level >= LOG_DEBUG)
+ gettimeofday(&start, NULL);
+
+ err = ioctl(fd, ioctl_cmd, cmd);
+
+ if (log_level >= LOG_DEBUG) {
+ gettimeofday(&end, NULL);
+ nvme_show_command(cmd, err);
+ nvme_show_latency(start, end);
+ }
+
+ if (err >= 0 && result)
+ *result = cmd->result;
+
+ return err;
+}
+
+int nvme_submit_passthru64(int fd, unsigned long ioctl_cmd,
+ struct nvme_passthru_cmd64 *cmd,
+ __u64 *result)
+{
+ struct timeval start;
+ struct timeval end;
+ int err;
+
+ if (log_level >= LOG_DEBUG)
+ gettimeofday(&start, NULL);
+
+
+ err = ioctl(fd, ioctl_cmd, cmd);
+
+ if (log_level >= LOG_DEBUG) {
+ gettimeofday(&end, NULL);
+ nvme_show_command64(cmd, err);
+ nvme_show_latency(start, end);
+ }
+
+ if (err >= 0 && result)
+ *result = cmd->result;
+
+ return err;
+}
diff --git a/util/logging.h b/util/logging.h
new file mode 100644
index 0000000..7b1814c
--- /dev/null
+++ b/util/logging.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef DEBUG_H_
+#define DEBUG_H_
+
+#include <stdbool.h>
+
+extern int log_level;
+
+int map_log_level(int verbose, bool quiet);
+
+#endif // DEBUG_H_
diff --git a/util/meson.build b/util/meson.build
index dfc683b..f5474cd 100644
--- a/util/meson.build
+++ b/util/meson.build
@@ -4,9 +4,11 @@ sources += [
'util/argconfig.c',
'util/base64.c',
'util/crc32.c',
+ 'util/logging.c',
'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);