From 8bb05ac73a5b448b339ce0bc8d396c82c459b47f Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 14 Apr 2024 21:33:32 +0200 Subject: Merging upstream version 2.40. Signed-off-by: Daniel Baumann --- libuuid/src/gen_uuid.c | 120 +++++++++++++++++++++++++++++++++++------------- libuuid/src/libuuid.sym | 9 ++++ libuuid/src/test_uuid.c | 20 +++++--- libuuid/src/uuid.h | 3 ++ libuuid/src/uuidP.h | 3 +- libuuid/src/uuid_time.c | 59 +++++++++++++++++++++++- 6 files changed, 174 insertions(+), 40 deletions(-) (limited to 'libuuid/src') 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 #include #ifdef HAVE_UNISTD_H #include @@ -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) { -- cgit v1.2.3