aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bash-completion/uuidgen2
-rw-r--r--libuuid/src/gen_uuid.c39
-rw-r--r--libuuid/src/libuuid.sym9
-rw-r--r--libuuid/src/uuid.h5
-rw-r--r--libuuid/src/uuid_time.c85
-rw-r--r--misc-utils/uuidgen.1.adoc7
-rw-r--r--misc-utils/uuidgen.c20
-rw-r--r--misc-utils/uuidparse.c15
-rw-r--r--tests/expected/uuid/uuidgen8
-rw-r--r--tests/expected/uuid/uuidparse5
-rwxr-xr-xtests/ts/uuid/uuidgen4
-rwxr-xr-xtests/ts/uuid/uuidparse3
12 files changed, 185 insertions, 17 deletions
diff --git a/bash-completion/uuidgen b/bash-completion/uuidgen
index 45f690d45e..96b91cd624 100644
--- a/bash-completion/uuidgen
+++ b/bash-completion/uuidgen
@@ -31,6 +31,8 @@ _uuidgen_module()
--md5
--count
--sha1
+ --time-v6
+ --time-v7
--hex
--help
--version
diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
index 59e8c23f01..aa353e4436 100644
--- a/libuuid/src/gen_uuid.c
+++ b/libuuid/src/gen_uuid.c
@@ -89,6 +89,7 @@
#include "c.h"
#include "md5.h"
#include "sha1.h"
+#include "timeutils.h"
#ifdef HAVE_TLS
#define THREAD_LOCAL static __thread
@@ -661,6 +662,44 @@ int uuid_generate_time_safe(uuid_t out)
return uuid_generate_time_generic(out);
}
+void uuid_generate_time_v6(uuid_t out)
+{
+ struct uuid uu = {};
+ uint64_t clock_reg;
+
+ clock_reg = get_clock_counter();
+
+ uu.time_low = clock_reg >> 28;
+ uu.time_mid = clock_reg >> 12;
+ uu.time_hi_and_version = (clock_reg & 0x0FFF) | (6 << 12);
+
+ ul_random_get_bytes(&uu.clock_seq, 8);
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+
+ uuid_pack(&uu, out);
+}
+
+// FIXME variable additional information
+void uuid_generate_time_v7(uuid_t out)
+{
+ struct timeval tv;
+ struct uuid uu;
+ uint64_t ms;
+
+ gettimeofday(&tv, NULL);
+
+ ms = tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
+
+ uu.time_low = ms >> 16;
+ uu.time_mid = ms;
+
+ ul_random_get_bytes(&uu.time_hi_and_version, 10);
+ uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | (7 << 12);
+ uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000;
+
+ uuid_pack(&uu, out);
+}
+
int __uuid_generate_random(uuid_t out, int *num)
{
diff --git a/libuuid/src/libuuid.sym b/libuuid/src/libuuid.sym
index 0f67ede0d5..4c4b4eba2e 100644
--- a/libuuid/src/libuuid.sym
+++ b/libuuid/src/libuuid.sym
@@ -60,6 +60,15 @@ global:
uuid_time64; /* only on 32bit architectures with 64bit time_t */
} UUID_2.36;
+/*
+ * version(s) since util-linux.2.41
+ */
+UUID_2.41 {
+global:
+ uuid_generate_time_v6;
+ uuid_generate_time_v7;
+} UUID_2.40;
+
/*
diff --git a/libuuid/src/uuid.h b/libuuid/src/uuid.h
index 2e3642cd63..2e0f70aa9c 100644
--- a/libuuid/src/uuid.h
+++ b/libuuid/src/uuid.h
@@ -59,6 +59,9 @@ typedef unsigned char uuid_t[16];
#define UUID_TYPE_DCE_MD5 3
#define UUID_TYPE_DCE_RANDOM 4
#define UUID_TYPE_DCE_SHA1 5
+#define UUID_TYPE_DCE_TIME_V6 6
+#define UUID_TYPE_DCE_TIME_V7 7
+#define UUID_TYPE_DCE_VENDOR 8
#define UUID_TYPE_SHIFT 4
#define UUID_TYPE_MASK 0xf
@@ -92,6 +95,8 @@ extern void uuid_generate(uuid_t out);
extern void uuid_generate_random(uuid_t out);
extern void uuid_generate_time(uuid_t out);
extern int uuid_generate_time_safe(uuid_t out);
+extern void uuid_generate_time_v6(uuid_t out);
+extern void uuid_generate_time_v7(uuid_t out);
extern void uuid_generate_md5(uuid_t out, const uuid_t ns, const char *name, size_t len);
extern void uuid_generate_sha1(uuid_t out, const uuid_t ns, const char *name, size_t len);
diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index 9b415b3ee7..d52c2f3070 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -53,30 +53,89 @@
#include <time.h>
#include "uuidP.h"
+#include "timeutils.h"
#undef uuid_time
/* prototype to make compiler happy */
time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
+static uint64_t gregorian_to_unix(uint64_t ts)
+{
+ return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000);
+}
+
+static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv)
+{
+ uint32_t high;
+ uint64_t clock_reg;
+
+ high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16);
+ clock_reg = uuid->time_low | ((uint64_t) high << 32);
+
+ clock_reg = gregorian_to_unix(clock_reg);
+ tv->tv_sec = clock_reg / 10000000;
+ tv->tv_usec = (clock_reg % 10000000) / 10;
+}
+
+static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv)
+{
+ uint64_t clock_reg;
+
+ clock_reg = uuid->time_low;
+ clock_reg <<= 16;
+ clock_reg |= uuid->time_mid;
+ clock_reg <<= 12;
+ clock_reg |= uuid->time_hi_and_version & 0xFFF;
+
+ clock_reg = gregorian_to_unix(clock_reg);
+ tv->tv_sec = clock_reg / 10000000;
+ tv->tv_usec = (clock_reg % 10000000) / 10;
+}
+
+static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv)
+{
+ uint64_t clock_reg;
+
+ clock_reg = uuid->time_low;
+ clock_reg <<= 16;
+ clock_reg |= uuid->time_mid;
+
+ tv->tv_sec = clock_reg / MSEC_PER_SEC;
+ tv->tv_usec = (clock_reg % MSEC_PER_SEC) * USEC_PER_MSEC;
+}
+
+static uint8_t __uuid_type(const struct uuid *uuid)
+{
+ return (uuid->time_hi_and_version >> 12) & 0xF;
+}
/* this function could be 32bit time_t and 32bit timeval or 64bit,
depending on compiler flags and architecture. */
time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv)
{
- struct timeval tv;
- struct uuid uuid;
- uint32_t high;
- uint64_t clock_reg;
+ struct timeval tv;
+ struct uuid uuid;
+ uint8_t type;
uuid_unpack(uu, &uuid);
+ type = __uuid_type(&uuid);
- high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
- clock_reg = uuid.time_low | ((uint64_t) high << 32);
-
- clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
- tv.tv_sec = clock_reg / 10000000;
- tv.tv_usec = (clock_reg % 10000000) / 10;
+ switch (type) {
+ case UUID_TYPE_DCE_TIME:
+ uuid_time_v1(&uuid, &tv);
+ break;
+ case UUID_TYPE_DCE_TIME_V6:
+ uuid_time_v6(&uuid, &tv);
+ break;
+ case UUID_TYPE_DCE_TIME_V7:
+ uuid_time_v7(&uuid, &tv);
+ break;
+ default:
+ tv.tv_sec = -1;
+ tv.tv_usec = -1;
+ break;
+ }
if (ret_tv)
*ret_tv = tv;
@@ -88,7 +147,7 @@ extern time_t uuid_time64(const uuid_t uu, struct timeval *ret_tv) __attribute__
#else
extern time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) __attribute__((weak, alias("__uuid_time")));
#endif
-
+
#if defined(__USE_TIME_BITS64) && defined(__GLIBC__)
struct timeval32
{
@@ -104,7 +163,7 @@ static inline int
in_time32_t_range(time_t t)
{
int32_t s;
-
+
s = t;
return s == t;
@@ -137,7 +196,7 @@ int uuid_type(const uuid_t uu)
struct uuid uuid;
uuid_unpack(uu, &uuid);
- return ((uuid.time_hi_and_version >> 12) & 0xF);
+ return __uuid_type(&uuid);
}
int uuid_variant(const uuid_t uu)
diff --git a/misc-utils/uuidgen.1.adoc b/misc-utils/uuidgen.1.adoc
index 659a7804dc..1d89fe43d6 100644
--- a/misc-utils/uuidgen.1.adoc
+++ b/misc-utils/uuidgen.1.adoc
@@ -42,6 +42,12 @@ Use MD5 as the hash algorithm.
*-s*, *--sha1*::
Use SHA1 as the hash algorithm.
+*-6*, *--time-v6*::
+Generate a time-based UUID. This method creates a UUID based on the system clock plus and is lexicographically sortable according to the contained timestamp.
+
+*-7*, *--time-v7*::
+Generate a time-based UUID. This method creates a UUID based on the system clock plus and is lexicographically sortable according to the contained timestamp.
+
*-n*, *--namespace* _namespace_::
Generate the hash with the _namespace_ prefix. The _namespace_ is UUID, or '@ns' where "ns" is well-known predefined UUID addressed by namespace name (see above).
@@ -71,6 +77,7 @@ uuidgen --sha1 --namespace @dns --name "www.example.com"
*uuidparse*(1),
*libuuid*(3),
link:https://tools.ietf.org/html/rfc4122[RFC 4122]
+link:https://tools.ietf.org/html/rfcXXXX[RFC XXXX]
include::man-common/bugreports.adoc[]
diff --git a/misc-utils/uuidgen.c b/misc-utils/uuidgen.c
index 57769c1f40..56dea3c711 100644
--- a/misc-utils/uuidgen.c
+++ b/misc-utils/uuidgen.c
@@ -40,6 +40,8 @@ static void __attribute__((__noreturn__)) usage(void)
fputs(_(" -m, --md5 generate md5 hash\n"), out);
fputs(_(" -C, --count <num> generate more uuids in loop\n"), out);
fputs(_(" -s, --sha1 generate sha1 hash\n"), out);
+ fputs(_(" -6, --time-v6 generate time-based v6 uuid\n"), out);
+ fputs(_(" -7, --time-v7 generate time-based v7 uuid\n"), out);
fputs(_(" -x, --hex interpret name as hex string\n"), out);
fputs(USAGE_SEPARATOR, out);
fprintf(out, USAGE_HELP_OPTIONS(21));
@@ -104,14 +106,16 @@ main (int argc, char *argv[])
{"md5", no_argument, NULL, 'm'},
{"count", required_argument, NULL, 'C'},
{"sha1", no_argument, NULL, 's'},
+ {"time-v6", no_argument, NULL, '6'},
+ {"time-v7", no_argument, NULL, '7'},
{"hex", no_argument, NULL, 'x'},
{NULL, 0, NULL, 0}
};
static const ul_excl_t excl[] = {
+ { '6', '7', 'm', 'r', 's', 't' },
{ 'C', 'm', 's' },
{ 'N', 'r', 't' },
- { 'm', 'r', 's', 't' },
{ 'n', 'r', 't' },
{ 0 }
};
@@ -122,7 +126,7 @@ main (int argc, char *argv[])
textdomain(PACKAGE);
close_stdout_atexit();
- while ((c = getopt_long(argc, argv, "C:rtVhn:N:msx", longopts, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "C:rtVhn:N:msx67", longopts, NULL)) != -1) {
err_exclusive_options(c, longopts, excl, excl_st);
@@ -151,6 +155,12 @@ main (int argc, char *argv[])
case 'x':
is_hex = 1;
break;
+ case '6':
+ do_type = UUID_TYPE_DCE_TIME_V6;
+ break;
+ case '7':
+ do_type = UUID_TYPE_DCE_TIME_V7;
+ break;
case 'h':
usage();
@@ -192,6 +202,12 @@ main (int argc, char *argv[])
case UUID_TYPE_DCE_TIME:
uuid_generate_time(uu);
break;
+ case UUID_TYPE_DCE_TIME_V6:
+ uuid_generate_time_v6(uu);
+ break;
+ case UUID_TYPE_DCE_TIME_V7:
+ uuid_generate_time_v7(uu);
+ break;
case UUID_TYPE_DCE_RANDOM:
uuid_generate_random(uu);
break;
diff --git a/misc-utils/uuidparse.c b/misc-utils/uuidparse.c
index 33d961c922..1336038118 100644
--- a/misc-utils/uuidparse.c
+++ b/misc-utils/uuidparse.c
@@ -203,6 +203,12 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid)
case UUID_TYPE_DCE_TIME:
str = xstrdup(_("time-based"));
break;
+ case UUID_TYPE_DCE_TIME_V6:
+ str = xstrdup(_("time-v6"));
+ break;
+ case UUID_TYPE_DCE_TIME_V7:
+ str = xstrdup(_("time-v7"));
+ break;
case UUID_TYPE_DCE_SECURITY:
str = xstrdup("DCE");
break;
@@ -215,6 +221,9 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid)
case UUID_TYPE_DCE_SHA1:
str = xstrdup(_("sha1-based"));
break;
+ case UUID_TYPE_DCE_VENDOR:
+ str = xstrdup(_("vendor"));
+ break;
default:
str = xstrdup(_("unknown"));
}
@@ -224,7 +233,11 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid)
str = xstrdup(_("invalid"));
break;
}
- if (variant == UUID_VARIANT_DCE && type == UUID_TYPE_DCE_TIME) {
+ if (variant != UUID_VARIANT_DCE)
+ break;
+ if (type == UUID_TYPE_DCE_TIME ||
+ type == UUID_TYPE_DCE_TIME_V6 ||
+ type == UUID_TYPE_DCE_TIME_V7) {
struct timeval tv;
char date_buf[ISO_BUFSIZ];
diff --git a/tests/expected/uuid/uuidgen b/tests/expected/uuid/uuidgen
index b0d1d98e74..7d517af8a3 100644
--- a/tests/expected/uuid/uuidgen
+++ b/tests/expected/uuid/uuidgen
@@ -2,7 +2,15 @@ option: -r
return values: 0 and 0
option: -t
return values: 0 and 0
+option: -6
+return values: 0 and 0
+option: -7
+return values: 0 and 0
option: --random
return values: 0 and 0
option: --time
return values: 0 and 0
+option: --time-v6
+return values: 0 and 0
+option: --time-v7
+return values: 0 and 0
diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse
index 5cac367559..9edb05e4e9 100644
--- a/tests/expected/uuid/uuidparse
+++ b/tests/expected/uuid/uuidparse
@@ -11,7 +11,7 @@ UUID VARIANT TYPE TIME
00000000-0000-3000-8000-000000000000 DCE name-based
00000000-0000-4000-8000-000000000000 DCE random
00000000-0000-5000-8000-000000000000 DCE sha1-based
-00000000-0000-6000-8000-000000000000 DCE unknown
+00000000-0000-6000-8000-000000000000 DCE time-v6 60038-03-11 05:36:10,955161+00:00
00000000-0000-0000-d000-000000000000 Microsoft
00000000-0000-1000-d000-000000000000 Microsoft
00000000-0000-2000-d000-000000000000 Microsoft
@@ -27,5 +27,8 @@ UUID VARIANT TYPE TIME
00000000-0000-5000-f000-000000000000 other
00000000-0000-6000-f000-000000000000 other
9b274c46-544a-11e7-a972-00037f500001 DCE time-based 2017-06-18 17:21:46,544647+00:00
+1ec9414c-232a-6b00-b3c8-9f6bdeced846 DCE time-v6 2022-02-22 19:22:22,000000+00:00
+017f22e2-79b2-7cc3-98c4-dc0c0c07398f DCE time-v7 2022-02-22 19:22:22,002000+00:00
+5c146b14-3c52-8afd-938a-375d0df1fbf6 DCE vendor
invalid-input invalid invalid invalid
return value: 0
diff --git a/tests/ts/uuid/uuidgen b/tests/ts/uuid/uuidgen
index cbaaefa7b3..48fab12f7b 100755
--- a/tests/ts/uuid/uuidgen
+++ b/tests/ts/uuid/uuidgen
@@ -37,8 +37,12 @@ test_flag() {
test_flag -r
test_flag -t
+test_flag -6
+test_flag -7
test_flag --random
test_flag --time
+test_flag --time-v6
+test_flag --time-v7
rm -f "$OUTPUT_FILE"
diff --git a/tests/ts/uuid/uuidparse b/tests/ts/uuid/uuidparse
index 915886c8f7..2903ce56dc 100755
--- a/tests/ts/uuid/uuidparse
+++ b/tests/ts/uuid/uuidparse
@@ -54,6 +54,9 @@ echo '00000000-0000-0000-0000-000000000000
00000000-0000-6000-f000-000000000000
9b274c46-544a-11e7-a972-00037f500001
+1ec9414c-232a-6b00-b3c8-9f6bdeced846
+017f22e2-79b2-7cc3-98c4-dc0c0c07398f
+5c146b14-3c52-8afd-938a-375d0df1fbf6
invalid-input' | $TS_CMD_UUIDPARSE >> $TS_OUTPUT 2>> $TS_ERRLOG
echo "return value: $?" >> $TS_OUTPUT