summaryrefslogtreecommitdiffstats
path: root/libuuid/src
diff options
context:
space:
mode:
Diffstat (limited to 'libuuid/src')
-rw-r--r--libuuid/src/gen_uuid.c120
-rw-r--r--libuuid/src/libuuid.sym9
-rw-r--r--libuuid/src/test_uuid.c20
-rw-r--r--libuuid/src/uuid.h3
-rw-r--r--libuuid/src/uuidP.h3
-rw-r--r--libuuid/src/uuid_time.c59
6 files changed, 174 insertions, 40 deletions
diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
index 826cd22..59e8c23 100644
--- a/libuuid/src/gen_uuid.c
+++ b/libuuid/src/gen_uuid.c
@@ -207,6 +207,28 @@ static int get_node_id(unsigned char *node_id)
return 0;
}
+enum { STATE_FD_ERROR = -1, STATE_FD_INIT = -2 };
+
+static int state_fd_init(const char *clock_file, FILE **fp)
+{
+ mode_t save_umask;
+ int state_fd;
+ FILE *state_f;
+
+ save_umask = umask(0);
+ state_fd = open(clock_file, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
+ (void) umask(save_umask);
+ if (state_fd != -1) {
+ state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
+ if (!state_f) {
+ close(state_fd);
+ state_fd = STATE_FD_ERROR;
+ } else
+ *fp = state_f;
+ }
+ return state_fd;
+}
+
/* Assume that the gettimeofday() has microsecond granularity */
#define MAX_ADJUSTMENT 10
/* Reserve a clock_seq value for the 'continuous clock' implementation */
@@ -223,32 +245,16 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
{
THREAD_LOCAL int adjustment = 0;
THREAD_LOCAL struct timeval last = {0, 0};
- THREAD_LOCAL int state_fd = -2;
+ THREAD_LOCAL int state_fd = STATE_FD_INIT;
THREAD_LOCAL FILE *state_f;
THREAD_LOCAL uint16_t clock_seq;
struct timeval tv;
uint64_t clock_reg;
- mode_t save_umask;
int ret = 0;
- if (state_fd == -1)
- ret = -1;
+ if (state_fd == STATE_FD_INIT)
+ state_fd = state_fd_init(LIBUUID_CLOCK_FILE, &state_f);
- if (state_fd == -2) {
- save_umask = umask(0);
- state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
- (void) umask(save_umask);
- if (state_fd != -1) {
- state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
- if (!state_f) {
- close(state_fd);
- state_fd = -1;
- ret = -1;
- }
- }
- else
- ret = -1;
- }
if (state_fd >= 0) {
rewind(state_f);
while (flock(state_fd, LOCK_EX) < 0) {
@@ -256,11 +262,13 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
continue;
fclose(state_f);
close(state_fd);
- state_fd = -1;
+ state_fd = STATE_FD_ERROR;
ret = -1;
break;
}
- }
+ } else
+ ret = -1;
+
if (state_fd >= 0) {
unsigned int cl;
unsigned long tv1, tv2;
@@ -355,44 +363,94 @@ static uint64_t get_clock_counter(void)
/*
* Get continuous clock value.
*
- * Return -1 if there is no further clock counter available,
+ * Return -1 if there is no valid clock counter available,
* otherwise return 0.
*
* This implementation doesn't deliver clock counters based on
* the current time because last_clock_reg is only incremented
* by the number of requested UUIDs.
* max_clock_offset is used to limit the offset of last_clock_reg.
+ * used/reserved UUIDs are written to LIBUUID_CLOCK_CONT_FILE.
*/
static int get_clock_cont(uint32_t *clock_high,
uint32_t *clock_low,
int num,
uint32_t max_clock_offset)
{
- /* 100ns based time offset according to RFC 4122. 4.1.4. */
+ /* all 64bit clock_reg values in this function represent '100ns ticks'
+ * due to the combination of tv_usec + MAX_ADJUSTMENT */
+
+ /* time offset according to RFC 4122. 4.1.4. */
const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
static uint64_t last_clock_reg = 0;
- uint64_t clock_reg;
+ static uint64_t saved_clock_reg = 0;
+ static int state_fd = STATE_FD_INIT;
+ static FILE *state_f = NULL;
+ uint64_t clock_reg, next_clock_reg;
- if (last_clock_reg == 0)
- last_clock_reg = get_clock_counter();
+ if (state_fd == STATE_FD_ERROR)
+ return -1;
clock_reg = get_clock_counter();
+
+ if (state_fd == STATE_FD_INIT) {
+ struct stat st;
+
+ state_fd = state_fd_init(LIBUUID_CLOCK_CONT_FILE, &state_f);
+ if (state_fd == STATE_FD_ERROR)
+ return -1;
+
+ if (fstat(state_fd, &st))
+ goto error;
+
+ if (st.st_size) {
+ rewind(state_f);
+ if (fscanf(state_f, "cont: %"SCNu64"\n", &last_clock_reg) != 1)
+ goto error;
+ } else
+ last_clock_reg = clock_reg;
+
+ saved_clock_reg = last_clock_reg;
+ }
+
if (max_clock_offset) {
- uint64_t clock_offset = max_clock_offset * 10000000ULL;
- if (last_clock_reg < (clock_reg - clock_offset))
- last_clock_reg = clock_reg - clock_offset;
+ uint64_t co = 10000000ULL * (uint64_t)max_clock_offset; // clock_offset in [100ns]
+
+ if ((last_clock_reg + co) < clock_reg)
+ last_clock_reg = clock_reg - co;
}
clock_reg += MAX_ADJUSTMENT;
- if ((last_clock_reg + num) >= clock_reg)
+ next_clock_reg = last_clock_reg + (uint64_t)num;
+ if (next_clock_reg >= clock_reg)
return -1;
+ if (next_clock_reg >= saved_clock_reg) {
+ uint64_t cl = next_clock_reg + 100000000ULL; // 10s interval in [100ns]
+ int l;
+
+ rewind(state_f);
+ l = fprintf(state_f, "cont: %020"PRIu64" \n", cl);
+ if (l < 30 || fflush(state_f))
+ goto error;
+ saved_clock_reg = cl;
+ }
+
*clock_high = (last_clock_reg + reg_offset) >> 32;
*clock_low = last_clock_reg + reg_offset;
- last_clock_reg += num;
+ last_clock_reg = next_clock_reg;
return 0;
+
+error:
+ if (state_fd >= 0)
+ close(state_fd);
+ if (state_f)
+ fclose(state_f);
+ state_fd = STATE_FD_ERROR;
+ state_f = NULL;
+ return -1;
}
#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)
diff --git a/libuuid/src/libuuid.sym b/libuuid/src/libuuid.sym
index 96372a8..0f67ede 100644
--- a/libuuid/src/libuuid.sym
+++ b/libuuid/src/libuuid.sym
@@ -52,6 +52,15 @@ global:
uuid_parse_range;
} UUID_2.31;
+/*
+ * version(s) since util-linux.2.40
+ */
+UUID_2.40 {
+global:
+ uuid_time64; /* only on 32bit architectures with 64bit time_t */
+} UUID_2.36;
+
+
/*
* __uuid_* this is not part of the official API, this is
diff --git a/libuuid/src/test_uuid.c b/libuuid/src/test_uuid.c
index 9907911..06d1589 100644
--- a/libuuid/src/test_uuid.c
+++ b/libuuid/src/test_uuid.c
@@ -66,24 +66,30 @@ static int test_uuid(const char * uuid, int isValid)
static int check_uuids_in_file(const char *file)
{
- int fd, ret = 0;
- size_t sz;
- char str[UUID_STR_LEN];
+ int ret = 0;
+ size_t alloc = 0;
+ ssize_t sz;
+ char *str = NULL;
+ FILE *f;
uuid_t uuidBits;
- if ((fd = open(file, O_RDONLY)) < 0) {
+ if ((f = fopen(file, "r")) == NULL) {
warn("%s", file);
return 1;
}
- while ((sz = read(fd, str, sizeof(str))) != 0) {
- str[sizeof(str) - 1] = '\0';
+ while ((sz = getline(&str, &alloc, f)) != -1) {
+ if (sz == 0 || str[0] == '\n')
+ continue;
+ if (str[sz - 1] == '\n')
+ str[sz - 1] = '\0';
if (uuid_parse(str, uuidBits)) {
warnx("%s: %s", file, str);
ret++;
}
}
- close(fd);
+ fclose(f);
+ free(str);
return ret;
}
diff --git a/libuuid/src/uuid.h b/libuuid/src/uuid.h
index e791abf..2e3642c 100644
--- a/libuuid/src/uuid.h
+++ b/libuuid/src/uuid.h
@@ -109,6 +109,9 @@ extern void uuid_unparse_lower(const uuid_t uu, char *out);
extern void uuid_unparse_upper(const uuid_t uu, char *out);
/* uuid_time.c */
+#if defined(__USE_TIME_BITS64) && defined(__GLIBC__)
+# define uuid_time uuid_time64
+#endif
extern time_t uuid_time(const uuid_t uu, struct timeval *ret_tv);
extern int uuid_type(const uuid_t uu);
extern int uuid_variant(const uuid_t uu);
diff --git a/libuuid/src/uuidP.h b/libuuid/src/uuidP.h
index 200702c..6face82 100644
--- a/libuuid/src/uuidP.h
+++ b/libuuid/src/uuidP.h
@@ -39,7 +39,8 @@
#include "uuid.h"
-#define LIBUUID_CLOCK_FILE "/var/lib/libuuid/clock.txt"
+#define LIBUUID_CLOCK_FILE _PATH_LOCALSTATEDIR "/lib/libuuid/clock.txt"
+#define LIBUUID_CLOCK_CONT_FILE _PATH_LOCALSTATEDIR "/lib/libuuid/clock-cont.txt"
/*
* Offset between 15-Oct-1582 and 1-Jan-70
diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c
index 6f07d51..9b415b3 100644
--- a/libuuid/src/uuid_time.c
+++ b/libuuid/src/uuid_time.c
@@ -40,6 +40,7 @@
#define UUID MYUUID
#endif
+#include <errno.h>
#include <stdio.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
@@ -53,7 +54,15 @@
#include "uuidP.h"
-time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
+#undef uuid_time
+
+/* prototype to make compiler happy */
+time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv);
+
+
+/* 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;
@@ -74,6 +83,54 @@ time_t uuid_time(const uuid_t uu, struct timeval *ret_tv)
return tv.tv_sec;
}
+#if defined(__USE_TIME_BITS64) && defined(__GLIBC__)
+extern time_t uuid_time64(const uuid_t uu, struct timeval *ret_tv) __attribute__((weak, alias("__uuid_time")));
+#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
+{
+ int32_t tv_sec;
+ int32_t tv_usec;
+};
+
+/* prototype to make compiler happy */
+int32_t __uuid_time32(const uuid_t uu, struct timeval32 *ret_tv);
+
+/* Check whether time fits in 32bit time_t. */
+static inline int
+in_time32_t_range(time_t t)
+{
+ int32_t s;
+
+ s = t;
+
+ return s == t;
+}
+
+int32_t __uuid_time32(const uuid_t uu, struct timeval32 *ret_tv)
+{
+ struct timeval tv;
+ time_t ret_time = __uuid_time(uu, &tv);
+
+ if (! in_time32_t_range(ret_time)) {
+ ret_tv->tv_sec = -1;
+ ret_tv->tv_usec = -1;
+ errno = EOVERFLOW;
+ return -1;
+ }
+
+ if (ret_tv) {
+ ret_tv->tv_sec = tv.tv_sec;
+ ret_tv->tv_usec = tv.tv_usec;
+ }
+
+ return tv.tv_sec;
+}
+extern int32_t uuid_time(const uuid_t uu, struct timeval32 *ret_tv) __attribute__((weak, alias("__uuid_time32")));
+#endif
int uuid_type(const uuid_t uu)
{