aboutsummaryrefslogtreecommitdiffstats
path: root/libpatch_create_timestamp_now.c
diff options
context:
space:
mode:
Diffstat (limited to 'libpatch_create_timestamp_now.c')
-rw-r--r--libpatch_create_timestamp_now.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/libpatch_create_timestamp_now.c b/libpatch_create_timestamp_now.c
new file mode 100644
index 0000000..b0bef09
--- /dev/null
+++ b/libpatch_create_timestamp_now.c
@@ -0,0 +1,73 @@
+/* See LICENSE file for copyright and license details. */
+#include "common.h"
+#ifdef __linux__
+# include <sys/timex.h>
+#endif
+
+
+size_t
+libpatch_create_timestamp_now(char *buf, size_t bufsize, signed frac, int zone, enum libpatch_style style)
+{
+ struct timespec ts;
+#ifdef __linux__
+ struct timex timex;
+ struct tm tm;
+ int r;
+#endif
+
+ if (frac < 0) {
+ if (clock_gettime(CLOCK_REALTIME, &ts)) {
+ frac = 9;
+ } else {
+ frac = 0;
+ while (ts.tv_nsec < 1000000000L) {
+ ts.tv_nsec *= 10;
+ frac += 1;
+ }
+ }
+ }
+
+#ifdef __linux__
+ memset(&timex, 0, sizeof(timex));
+ if (frac > 6)
+ timex.status = ADJ_NANO;
+ r = adjtimex(&timex);
+ if (r == -1) {
+ if (errno == ENOSYS)
+ goto fallback;
+ return 0;
+ }
+
+ if (timex.time.tv_sec % (24 * 60 * 60) == 0) {
+ if (r == TIME_INS) {
+ timex.time.tv_sec -= 1;
+ if (!localtime_r(&timex.time.tv_sec, &tm))
+ return 0;
+ tm.tm_sec += 1;
+ } else if (r == TIME_DEL) {
+ timex.time.tv_sec += 1;
+ if (!localtime_r(&timex.time.tv_sec, &tm))
+ return 0;
+ } else {
+ if (!localtime_r(&timex.time.tv_sec, &tm))
+ return 0;
+ }
+ } else if (r == TIME_OOP) {
+ if (!localtime_r(&timex.time.tv_sec, &tm))
+ return 0;
+ tm.tm_sec += 1;
+ } else {
+ if (!localtime_r(&timex.time.tv_sec, &tm))
+ return 0;
+ }
+
+ return libpatch_create_timestamp(buf, bufsize, &tm, (uintmax_t)timex.time.tv_usec,
+ frac > 6 ? 9U : 6U, (unsigned)frac, zone, style);
+
+fallback:
+#endif
+
+ if (clock_gettime(CLOCK_REALTIME, &ts))
+ return 0;
+ return libpatch_create_timestamp_ts(buf, bufsize, &ts, (unsigned)frac, zone, style);
+}