From 71c25d1cf741babf65891f71a0d9669b7a2369a1 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 13 Oct 2022 17:05:50 +0200 Subject: [PATCH] util: Add simple UUID type Provide our own UUID type as there is no point to have a dependency on libuuid just for a couple function we use. Signed-off-by: Daniel Wagner --- meson.build | 4 -- src/libnvme.map | 3 ++ src/meson.build | 9 ---- src/nvme/fabrics.c | 26 +++++----- src/nvme/private.h | 4 +- src/nvme/tree.c | 4 +- src/nvme/tree.h | 3 +- src/nvme/util.c | 56 +++++++++++++++++++++ src/nvme/util.h | 32 ++++++++++++ test/meson.build | 11 ++++- test/test.c | 7 ++- test/uuid.c | 120 +++++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 241 insertions(+), 38 deletions(-) create mode 100644 test/uuid.c diff --git a/meson.build b/meson.build index 07f098de..4735a231 100644 --- a/meson.build +++ b/meson.build @@ -52,10 +52,6 @@ conf.set('PROJECT_VERSION', '"@0@"'.format(meson.project_version())) conf.set('SYSCONFDIR', '"@0@"'.format(sysconfdir)) -# Check for libuuid availability -libuuid_dep = dependency('uuid', required: true, fallback : ['uuid', 'uuid_dep']) -conf.set('CONFIG_LIBUUID', libuuid_dep.found(), description: 'Is libuuid required?') - # Check for json-c availability json_c_dep = dependency('json-c', version: '>=0.13', diff --git a/src/libnvme.map b/src/libnvme.map index d619f395..be9bca35 100644 --- a/src/libnvme.map +++ b/src/libnvme.map @@ -7,6 +7,9 @@ LIBNVME_1_2 { nvmf_get_discovery_wargs; nvme_get_feature_length2; nvme_ctrl_is_persistent; + nvme_uuid_from_string; + nvme_uuid_to_string; + nvme_uuid_random; }; LIBNVME_1_1 { diff --git a/src/meson.build b/src/meson.build index 3076be6b..9e49a077 100644 --- a/src/meson.build +++ b/src/meson.build @@ -28,13 +28,11 @@ if conf.get('CONFIG_JSONC') endif deps = [ - libuuid_dep, json_c_dep, openssl_dep, ] mi_deps = [ - libuuid_dep, libsystemd_dep, ] @@ -68,7 +66,6 @@ pkg.generate(libnvme, libnvme_dep = declare_dependency( include_directories: ['.'], dependencies: [ - libuuid_dep.partial_dependency(compile_args: true, includes: true), json_c_dep.partial_dependency(compile_args: true, includes: true), ], link_with: libnvme, @@ -88,9 +85,6 @@ libnvme_mi = library( libnvme_mi_dep = declare_dependency( include_directories: ['.'], - dependencies: [ - libuuid_dep.partial_dependency(compile_args: true, includes: true), - ], link_with: libnvme_mi, ) @@ -107,9 +101,6 @@ libnvme_mi_test = library( libnvme_mi_test_dep = declare_dependency( include_directories: ['.'], - dependencies: [ - libuuid_dep.partial_dependency(compile_args: true, includes: true), - ], link_with: libnvme_mi_test, ) diff --git a/src/nvme/fabrics.c b/src/nvme/fabrics.c index 1a4ac4a5..7c2b3711 100644 --- a/src/nvme/fabrics.c +++ b/src/nvme/fabrics.c @@ -39,7 +39,6 @@ #include "private.h" #define NVMF_HOSTID_SIZE 37 -#define UUID_SIZE 37 /* 1b4e28ba-2fa1-11d2-883f-0016d3cca427 + \0 */ #define NVMF_HOSTNQN_FILE SYSCONFDIR "/nvme/hostnqn" #define NVMF_HOSTID_FILE SYSCONFDIR "/nvme/hostid" @@ -929,8 +928,8 @@ static int uuid_from_device_tree(char *system_uuid) if (f < 0) return -ENXIO; - memset(system_uuid, 0, UUID_SIZE); - len = read(f, system_uuid, UUID_SIZE - 1); + memset(system_uuid, 0, NVME_UUID_LEN_STRING); + len = read(f, system_uuid, NVME_UUID_LEN_STRING - 1); close(f); if (len < 0) return -ENXIO; @@ -1018,7 +1017,7 @@ static int uuid_from_product_uuid(char *system_uuid) system_uuid[0] = '\0'; nread = getline(&line, &len, stream); - if (nread != UUID_SIZE) { + if (nread != NVME_UUID_LEN_STRING) { ret = -ENXIO; goto out; } @@ -1026,8 +1025,8 @@ static int uuid_from_product_uuid(char *system_uuid) /* The kernel is handling the byte swapping according DMTF * SMBIOS 3.0 Section 7.2.1 System UUID */ - memcpy(system_uuid, line, UUID_SIZE - 1); - system_uuid[UUID_SIZE - 1] = '\0'; + memcpy(system_uuid, line, NVME_UUID_LEN_STRING - 1); + system_uuid[NVME_UUID_LEN_STRING - 1] = '\0'; ret = 0; @@ -1063,16 +1062,17 @@ char *nvmf_hostnqn_generate() { char *hostnqn; int ret; - char uuid_str[UUID_SIZE]; - uuid_t uuid; + char uuid_str[NVME_UUID_LEN_STRING]; + unsigned char uuid[NVME_UUID_LEN]; ret = uuid_from_dmi(uuid_str); if (ret < 0) { ret = uuid_from_device_tree(uuid_str); } if (ret < 0) { - uuid_generate_random(uuid); - uuid_unparse_lower(uuid, uuid_str); + if (nvme_uuid_random(uuid) < 0) + memset(uuid, 0, NVME_UUID_LEN); + nvme_uuid_to_string(uuid, uuid_str); } if (asprintf(&hostnqn, "nqn.2014-08.org.nvmexpress:uuid:%s", uuid_str) < 0) @@ -1125,7 +1125,7 @@ static __u32 nvmf_get_tel(const char *hostsymname) __u16 len; /* Host ID is mandatory */ - tel += nvmf_exat_size(sizeof(uuid_t)); + tel += nvmf_exat_size(NVME_UUID_LEN_STRING); /* Symbolic name is optional */ len = hostsymname ? strlen(hostsymname) : 0; @@ -1169,8 +1169,8 @@ static void nvmf_fill_die(struct nvmf_ext_die *die, struct nvme_host *h, numexat++; exat = die->exat; exat->exattype = cpu_to_le16(NVMF_EXATTYPE_HOSTID); - exat->exatlen = cpu_to_le16(nvmf_exat_len(sizeof(uuid_t))); - uuid_parse(h->hostid, exat->exatval); + exat->exatlen = cpu_to_le16(nvmf_exat_len(NVME_UUID_LEN)); + nvme_uuid_from_string(h->hostid, exat->exatval); /* Extended Attribute for the Symbolic Name (optional) */ symname_len = h->hostsymname ? strlen(h->hostsymname) : 0; diff --git a/src/nvme/private.h b/src/nvme/private.h index 0aac4300..cdd1bbf5 100644 --- a/src/nvme/private.h +++ b/src/nvme/private.h @@ -16,8 +16,6 @@ #include "fabrics.h" #include "mi.h" -#include - extern const char *nvme_ctrl_sysfs_dir; extern const char *nvme_subsys_sysfs_dir; @@ -57,7 +55,7 @@ struct nvme_ns { uint8_t eui64[8]; uint8_t nguid[16]; - uuid_t uuid; + unsigned char uuid[NVME_UUID_LEN]; enum nvme_csi csi; }; diff --git a/src/nvme/tree.c b/src/nvme/tree.c index 193051ca..b992824d 100644 --- a/src/nvme/tree.c +++ b/src/nvme/tree.c @@ -1551,9 +1551,9 @@ const uint8_t *nvme_ns_get_nguid(nvme_ns_t n) return n->nguid; } -void nvme_ns_get_uuid(nvme_ns_t n, uuid_t out) +void nvme_ns_get_uuid(nvme_ns_t n, unsigned char out[NVME_UUID_LEN]) { - uuid_copy(out, n->uuid); + memcpy(out, n->uuid, NVME_UUID_LEN); } int nvme_ns_identify(nvme_ns_t n, struct nvme_id_ns *ns) diff --git a/src/nvme/tree.h b/src/nvme/tree.h index 379dcb1d..156cb791 100644 --- a/src/nvme/tree.h +++ b/src/nvme/tree.h @@ -15,7 +15,6 @@ #include #include -#include #include "ioctl.h" #include "util.h" @@ -521,7 +520,7 @@ const uint8_t *nvme_ns_get_nguid(nvme_ns_t n); * * Copies the namespace's uuid into @out */ -void nvme_ns_get_uuid(nvme_ns_t n, uuid_t out); +void nvme_ns_get_uuid(nvme_ns_t n, unsigned char out[NVME_UUID_LEN]); /** * nvme_ns_get_sysfs_dir() - sysfs directory of a namespace diff --git a/src/nvme/util.c b/src/nvme/util.c index 653bb362..c61dbe92 100644 --- a/src/nvme/util.c +++ b/src/nvme/util.c @@ -11,6 +11,8 @@ #include #include +#include +#include #include #include #include @@ -833,3 +835,57 @@ const char *nvme_get_version(enum nvme_version type) return "n/a"; } } + +int nvme_uuid_to_string(unsigned char uuid[NVME_UUID_LEN], char *str) +{ + int n; + n = snprintf(str, NVME_UUID_LEN_STRING, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5], + uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]); + return n != NVME_UUID_LEN_STRING - 1 ? -EINVAL : 0; +} + +int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN]) +{ + int n; + + n = sscanf(str, + "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-" + "%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", + &uuid[0], &uuid[1], &uuid[2], &uuid[3], &uuid[4], &uuid[5], + &uuid[6], &uuid[7], &uuid[8], &uuid[9], &uuid[10], &uuid[11], + &uuid[12], &uuid[13], &uuid[14], &uuid[15]); + return n != NVME_UUID_LEN ? -EINVAL : 0; + +} + +int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]) +{ + int f; + ssize_t n; + + f = open("/dev/urandom", O_RDONLY); + if (f < 0) + return -errno; + n = read(f, uuid, NVME_UUID_LEN); + if (n < 0) { + close(f); + return -errno; + } else if (n != NVME_UUID_LEN) { + close(f); + return -EIO; + } + + /* + * See https://www.rfc-editor.org/rfc/rfc4122#section-4.4 + * Algorithms for Creating a UUID from Truly Random + * or Pseudo-Random Numbers + */ + uuid[6] = (uuid[6] & 0x0f) | 0x40; + uuid[8] = (uuid[8] & 0x3f) | 0x80; + + return 0; +} diff --git a/src/nvme/util.h b/src/nvme/util.h index 6c3163db..73be6e96 100644 --- a/src/nvme/util.h +++ b/src/nvme/util.h @@ -606,4 +606,36 @@ enum nvme_version { */ const char *nvme_get_version(enum nvme_version type); +#define NVME_UUID_LEN_STRING 37 /* 1b4e28ba-2fa1-11d2-883f-0016d3cca427 + \0 */ +#define NVME_UUID_LEN 16 + +/** + * nvme_uuid_to_string - Return string represenation of encoded UUID + * @uuid: Binary encoded input UUID + * @str: Output string represenation of UUID + * + * Return: Returns error code if type conversion fails. + */ +int nvme_uuid_to_string(unsigned char uuid[NVME_UUID_LEN], char *str); + +/** + * nvme_uuid_from_string - Return encoded UUID represenation of string UUID + * @uuid: Binary encoded input UUID + * @str: Output string represenation of UUID + * + * Return: Returns error code if type conversion fails. + */ +int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN]); + +/** + * nvme_uuid_random - Generate random UUID + * @uuid: Generated random UUID + * + * Generate random number according + * https://www.rfc-editor.org/rfc/rfc4122#section-4.4 + * + * Return: Returns error code if generating of random number fails. + */ +int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]); + #endif /* _LIBNVME_UTIL_H */ diff --git a/test/meson.build b/test/meson.build index 00c9ceb2..d90f835e 100644 --- a/test/meson.build +++ b/test/meson.build @@ -12,7 +12,7 @@ main = executable( 'main-test', ['test.c'], - dependencies: [libnvme_dep, libuuid_dep], + dependencies: [libnvme_dep], include_directories: [incdir, internal_incdir] ) @@ -56,3 +56,12 @@ mi_mctp = executable( ) test('mi-mctp', mi_mctp) + +uuid = executable( + 'test-uuid', + ['uuid.c'], + dependencies: libnvme_dep, + include_directories: [incdir, internal_incdir] +) + +test('uuid', uuid) diff --git a/test/test.c b/test/test.c index bc5393ba..2f24e1ec 100644 --- a/test/test.c +++ b/test/test.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -377,8 +376,8 @@ int main(int argc, char **argv) nvme_ctrl_get_state(c)); nvme_ctrl_for_each_ns(c, n) { - char uuid_str[40]; - uuid_t uuid; + char uuid_str[NVME_UUID_LEN_STRING]; + unsigned char uuid[NVME_UUID_LEN]; printf(" `- %s lba size:%d lba max:%" PRIu64 "\n", nvme_ns_get_name(n), nvme_ns_get_lba_size(n), @@ -388,7 +387,7 @@ int main(int argc, char **argv) printf(" nguid:"); print_hex(nvme_ns_get_nguid(n), 16); nvme_ns_get_uuid(n, uuid); - uuid_unparse_lower(uuid, uuid_str); + nvme_uuid_to_string(uuid, uuid_str); printf(" uuid:%s csi:%d\n", uuid_str, nvme_ns_get_csi(n)); } diff --git a/test/uuid.c b/test/uuid.c new file mode 100644 index 00000000..91464531 --- /dev/null +++ b/test/uuid.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/** + * This file is part of libnvme. + * Copyright (c) 2022 Daniel Wagner, SUSE Software Solutions + */ + +#include +#include + +#include + +#include + +static int test_rc; + +struct test_data { + unsigned char uuid[NVME_UUID_LEN]; + const char *str; +}; + +static struct test_data test_data[] = { + { { 0 }, "00000000-0000-0000-0000-000000000000" }, + { { [0 ... 15] = 0xff }, "ffffffff-ffff-ffff-ffff-ffffffffffff" }, + { { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0f, 0x10 }, + "00010203-0405-0607-0809-0a0b0c0d0f10" }, +}; + +static void check_str(const char *exp, const char *res) +{ + if (!strcmp(res, exp)) + return; + + printf("ERROR: got '%s', expected '%s'\n", res, exp); + + test_rc = 1; +} + +static void print_uuid_hex(const unsigned char uuid[NVME_UUID_LEN]) +{ + for (int i = 0; i < NVME_UUID_LEN; i++) + printf("%02x", uuid[i]); +} + +static void check_uuid(unsigned char exp[NVME_UUID_LEN], + unsigned char res[NVME_UUID_LEN]) +{ + if (!memcmp(exp, res, NVME_UUID_LEN)) + return; + + printf("ERROR: got '"); + print_uuid_hex(exp); + printf("', expected '"); + print_uuid_hex(res); + printf("'\n"); +} + +static void tostr_test(struct test_data *test) +{ + char str[NVME_UUID_LEN_STRING]; + + if (nvme_uuid_to_string(test->uuid, str)) { + test_rc = 1; + printf("ERROR: nvme_uuid_to_string() failed\n"); + return; + } + check_str(test->str, str); +} + +static void fromstr_test(struct test_data *test) +{ + + unsigned char uuid[NVME_UUID_LEN]; + + if (nvme_uuid_from_string(test->str, uuid)) { + test_rc = 1; + printf("ERROR: nvme_uuid_from_string() failed\n"); + return; + } + check_uuid(test->uuid, uuid); +} + +static void random_uuid_test(void) +{ + unsigned char uuid1[NVME_UUID_LEN], uuid2[NVME_UUID_LEN]; + char str1[NVME_UUID_LEN_STRING], str2[NVME_UUID_LEN_STRING]; + + if (nvme_uuid_random(uuid1) || nvme_uuid_random(uuid2)) { + test_rc = 1; + printf("ERROR: nvme_uuid_random() failed\n"); + return; + } + + if (!memcmp(uuid1, uuid2, NVME_UUID_LEN)) { + test_rc = 1; + printf("ERROR: generated random numbers are equal\n"); + return; + } + + if (nvme_uuid_to_string(uuid1, str1) || + nvme_uuid_to_string(uuid2, str2)) { + test_rc = 1; + printf("ERROR: could not stringify randomly generated UUID\n"); + return; + } + printf("PASS: generated UUIDs %s %s\n", str1, str2); +} + +int main(void) +{ + for (int i = 0; i < ARRAY_SIZE(test_data); i++) + tostr_test(&test_data[i]); + + for (int i = 0; i < ARRAY_SIZE(test_data); i++) + fromstr_test(&test_data[i]); + + random_uuid_test(); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} -- 2.50.1