Compare commits
35 Commits
2239ab6271
...
70c5499709
Author | SHA1 | Date |
---|---|---|
|
70c5499709 | |
|
2ccbb69032 | |
|
49e25c1bd4 | |
|
b9d8175545 | |
|
0fef08bbc4 | |
|
b304e34d56 | |
|
40e3432faf | |
|
9ba552a1b5 | |
|
54f99f8269 | |
|
263a1ec1f1 | |
|
2d8f7bc57a | |
|
5948a2be00 | |
|
2f36596b6d | |
|
7e0555f2c2 | |
|
8730de52de | |
|
3eeab1d368 | |
|
8990553795 | |
|
fb76556f95 | |
|
d9aef1d8d9 | |
|
72814b830c | |
|
4a455be70a | |
|
0305241095 | |
|
ef75110afb | |
|
0482958335 | |
|
f6257155cc | |
|
d93fb760d5 | |
|
ee5f69c0c3 | |
|
bb570bbbf2 | |
|
42a8e34e80 | |
|
60471c9f52 | |
|
4227cbfa94 | |
|
2799f04cad | |
|
e9e57dc9af | |
|
9033153c47 | |
|
97c57ca604 |
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2023 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -37,6 +37,8 @@ extern "C" {
|
|||
#define CLOCK_THREAD_CPUTIME_ID 8
|
||||
#define CLOCK_THREAD_SYSTIME_ID 9
|
||||
|
||||
#define CLOCK_REALTIME_HAS_LEAP_SECONDS 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sortix/clock.h>
|
||||
#include <sortix/fcntl.h>
|
||||
#include <sortix/mman.h>
|
||||
#include <sortix/stat.h>
|
||||
|
@ -429,70 +428,6 @@ static void SystemIdleThread(void* /*user*/)
|
|||
}
|
||||
}
|
||||
|
||||
kthread_mutex_t driver_threads_lock = KTHREAD_MUTEX_INITIALIZER;
|
||||
kthread_cond_t driver_threads_cond = KTHREAD_COND_INITIALIZER;
|
||||
size_t driver_threads_done = 0;
|
||||
size_t driver_threads_total = 0;
|
||||
|
||||
// Parallelize the initialization of slow drivers.
|
||||
static void RunDriverThread(void (*entry)(void*), void* user, const char* name)
|
||||
{
|
||||
kthread_mutex_lock(&driver_threads_lock);
|
||||
driver_threads_total++;
|
||||
kthread_mutex_unlock(&driver_threads_lock);
|
||||
if ( !RunKernelThread(entry, user, name) )
|
||||
PanicF("RunKernelThread: %s", name);
|
||||
}
|
||||
|
||||
static void FinishedDriverThread()
|
||||
{
|
||||
ScopedLock lock(&driver_threads_lock);
|
||||
driver_threads_done++;
|
||||
kthread_cond_broadcast(&driver_threads_cond);
|
||||
}
|
||||
|
||||
struct PS2ThreadCtx
|
||||
{
|
||||
PS2Keyboard* keyboard;
|
||||
PS2Mouse* mouse;
|
||||
};
|
||||
|
||||
static void PS2Thread(void* user)
|
||||
{
|
||||
struct PS2ThreadCtx* ctx = (struct PS2ThreadCtx*) user;
|
||||
PS2::Init(ctx->keyboard, ctx->mouse);
|
||||
FinishedDriverThread();
|
||||
}
|
||||
|
||||
struct DevCtx
|
||||
{
|
||||
Ref<Descriptor> dev;
|
||||
};
|
||||
|
||||
static void AHCIThread(void* user)
|
||||
{
|
||||
AHCI::Init("/dev", ((struct DevCtx*) user)->dev);
|
||||
FinishedDriverThread();
|
||||
}
|
||||
|
||||
static void ATAThread(void* user)
|
||||
{
|
||||
ATA::Init("/dev", ((struct DevCtx*) user)->dev);
|
||||
FinishedDriverThread();
|
||||
}
|
||||
|
||||
static void BGAThread(void* /*user*/)
|
||||
{
|
||||
BGA::Init();
|
||||
FinishedDriverThread();
|
||||
}
|
||||
|
||||
static void EMThread(void* user)
|
||||
{
|
||||
EM::Init("/dev", ((struct DevCtx*) user)->dev);
|
||||
FinishedDriverThread();
|
||||
}
|
||||
|
||||
static void BootThread(void* /*user*/)
|
||||
{
|
||||
//
|
||||
|
@ -576,7 +511,6 @@ static void BootThread(void* /*user*/)
|
|||
Ref<Descriptor> slashdev = droot->open(&ctx, "dev", O_READ | O_DIRECTORY);
|
||||
if ( !slashdev )
|
||||
Panic("Unable to create descriptor for RAM filesystem /dev directory.");
|
||||
struct DevCtx dev_ctx = { slashdev };
|
||||
|
||||
// Initialize the keyboard.
|
||||
PS2Keyboard* keyboard = new PS2Keyboard();
|
||||
|
@ -594,8 +528,7 @@ static void BootThread(void* /*user*/)
|
|||
Panic("Could not allocate PS2 Mouse driver");
|
||||
|
||||
// Initialize the PS/2 controller.
|
||||
struct PS2ThreadCtx ps2_context = { keyboard, mouse };
|
||||
RunDriverThread(PS2Thread, &ps2_context, "ps2");
|
||||
PS2::Init(keyboard, mouse);
|
||||
|
||||
// Register /dev/tty as the current-terminal factory.
|
||||
Ref<Inode> tty(new DevTTY(slashdev->dev, 0666, 0, 0));
|
||||
|
@ -683,13 +616,13 @@ static void BootThread(void* /*user*/)
|
|||
#endif
|
||||
|
||||
// Initialize AHCI devices.
|
||||
RunDriverThread(AHCIThread, &dev_ctx, "ahci");
|
||||
AHCI::Init("/dev", slashdev);
|
||||
|
||||
// Initialize ATA devices.
|
||||
RunDriverThread(ATAThread, &dev_ctx, "ata");
|
||||
ATA::Init("/dev", slashdev);
|
||||
|
||||
// Initialize the BGA driver.
|
||||
RunDriverThread(BGAThread, NULL, "bga");
|
||||
BGA::Init();
|
||||
|
||||
// Initialize the filesystem network.
|
||||
NetFS::Init();
|
||||
|
@ -711,15 +644,9 @@ static void BootThread(void* /*user*/)
|
|||
{
|
||||
// Initialize the EM driver.
|
||||
if ( enable_em )
|
||||
RunDriverThread(EMThread, &dev_ctx, "em");
|
||||
EM::Init("/dev", slashdev);
|
||||
}
|
||||
|
||||
// Await the drivers initialized in the background threads.
|
||||
kthread_mutex_lock(&driver_threads_lock);
|
||||
while ( driver_threads_done != driver_threads_total )
|
||||
kthread_cond_wait(&driver_threads_cond, &driver_threads_lock);
|
||||
kthread_mutex_unlock(&driver_threads_lock);
|
||||
|
||||
//
|
||||
// Stage 6. Executing Hosted Environment ("User-Space")
|
||||
//
|
||||
|
|
|
@ -780,6 +780,10 @@ scram/scram.2 \
|
|||
sys/dnsconfig/getdnsconfig.2 \
|
||||
sys/dnsconfig/setdnsconfig.2 \
|
||||
|
||||
MANPAGES3=\
|
||||
time/add_leap_seconds.3 \
|
||||
time/sub_leap_seconds.3 \
|
||||
|
||||
HEADERS:=$(shell find include -type f)
|
||||
|
||||
LIBK_OBJS:=$(FREEOBJS:.o=.libk.o)
|
||||
|
@ -906,3 +910,5 @@ install-libs-kernel: $(INSTALLLIBSKERNEL)
|
|||
install-man:
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man2
|
||||
cp $(MANPAGES2) $(DESTDIR)$(MANDIR)/man2
|
||||
mkdir -p $(DESTDIR)$(MANDIR)/man3
|
||||
cp $(MANPAGES3) $(DESTDIR)$(MANDIR)/man3
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2011, 2012, 2013, 2014, 2023 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -163,7 +163,9 @@ time_t timegm(struct tm*);
|
|||
#if __USE_SORTIX
|
||||
int clock_gettimeres(clockid_t, struct timespec*, struct timespec*);
|
||||
int clock_settimeres(clockid_t, const struct timespec*, const struct timespec*);
|
||||
int timens(struct tmns* tmns);
|
||||
int timens(struct tmns*);
|
||||
int sub_leap_seconds(time_t*);
|
||||
int add_leap_seconds(time_t*);
|
||||
#endif
|
||||
|
||||
extern char* tzname[2];
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
.Dd March 26, 2023
|
||||
.Dt ADD_LEAP_SECONDS 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm add_leap_seconds ,
|
||||
.Nm sub_leap_seconds
|
||||
.Nd convert between utc and tai-10 timestamps
|
||||
.Sh SYNOPSIS
|
||||
.In time.h
|
||||
.Ft int
|
||||
.Fn add_leap_seconds "time_t *timestamp"
|
||||
.Ft int
|
||||
.Fn sub_leap_seconds "time_t *timestamp"
|
||||
.Sh DESCRIPTION
|
||||
.Fn add_leap_seconds
|
||||
adds leap seconds to the UTC
|
||||
.Fa timestamp
|
||||
to give the corresponding TAI-10 timestamp.
|
||||
.Pp
|
||||
.Fn sub_leap_seconds
|
||||
subtracts leap seconds from the TAI-10
|
||||
.Fa timestamp
|
||||
to give the corresponding UTC timestamp.
|
||||
.Pp
|
||||
Leap seconds are announced usually six months in advanced by the
|
||||
International Earth Rotation and Reference Systems Service (IERS) in Bulletin C.
|
||||
Leap seconds can be added or removed at the end of the June or December (UTC)
|
||||
where the last minute can be 61 or 59 seconds.
|
||||
Leap seconds correct the difference between solar time and civil time when
|
||||
planetary rotation varies.
|
||||
Leap seconds have never been removed as of mid 2023.
|
||||
.Pp
|
||||
.Dv CLOCK_REALTIME
|
||||
on this system is in the TAI-10 format which measures the number of actual
|
||||
seconds including leap seconds that has happened since the Unix epoch of
|
||||
1970-01-01 00:00:00 UTC.
|
||||
The inclusion of leap seconds is advertised by the
|
||||
.Dv CLOCK_REALTIME_HAS_LEAP_SECONDS
|
||||
definition.
|
||||
This violates POSIX's requirement that
|
||||
.Dv CLOCK_REALTIME
|
||||
is in UTC, which pretends leap seconds don't happen.
|
||||
The
|
||||
.Fn add_leap_seconds
|
||||
and
|
||||
.Fn sub_leap_seconds
|
||||
functions are useful when exchanging timestamps with other operating systems.
|
||||
.Pp
|
||||
TAI-10 is International Atomic Time (TAI) subtracted by 10 seconds so the epoch
|
||||
is the same moment in TAI-10 and UTC.
|
||||
.Pp
|
||||
TAI-10 has the advantage that every actual past moment in time has an unique and
|
||||
unambiguous and continuous representation.
|
||||
The time difference between two TAI-10 timestamps can be calculated as a simple
|
||||
subtraction.
|
||||
Durations can be simply added to TAI-10 timestamps to produce the the timestamp
|
||||
changed by that many seconds.
|
||||
However it's not possible to compute which TAI10 timestamp corresponds to a
|
||||
calendar date and time more than 6 months in the future, as the leap seconds
|
||||
have not been announced yet.
|
||||
The system leap second table needs to be up to date in order to perform properly
|
||||
between TAI-10 and calendar time.
|
||||
TAI-10 is the most useful format when dealing with relative times, as it's
|
||||
guaranteed a certain amount of time has elapsed.
|
||||
.Pp
|
||||
UTC has the disadvantage that two different seconds can have the same timestamp
|
||||
when leap seconds are removed, and UTC can be discontinuous if a leap second
|
||||
removed where a timestamp could correspond to no actual moment in time.
|
||||
The actual time between two UTC timestamps cannot be computed by a simple
|
||||
subtraction (a leap second table is required) and durations cannot simply be
|
||||
added to wait for a particular amount of time.
|
||||
UTC is the most useful format when dealing with calendar times, as it's always
|
||||
possible to losslessly convert UTC to and from calendar time.
|
||||
.Sh RETURN VALUES
|
||||
On success 1 is returned.
|
||||
.Pp
|
||||
0 is returned when the input timestamp has no representation in the output
|
||||
format or is ambigous.
|
||||
The output timestamp will be the best approximation.
|
||||
This can happen in
|
||||
.Fn sub_leap_seconds
|
||||
when converting from TAI-10 to UTC and a leap second has been
|
||||
inserted, or in
|
||||
.Fn add_leap_seconds
|
||||
when converting from UTC to TAI-10 and a leap second has been removed (which has
|
||||
never happened so far).
|
||||
.Pp
|
||||
-1 is returned when the input timestamp is too far in the future and it is
|
||||
unknown whether a leap second will occur.
|
||||
The output timestamp will be the best approximation.
|
||||
The accurate result can be obtained when the system leap second table has been
|
||||
updated.
|
||||
.Sh SEE ALSO
|
||||
.Xr clock_gettime 2 ,
|
||||
.Xr gmtime_r 3 ,
|
||||
.Xr localtime_r 3 ,
|
||||
.Xr mktime 3 ,
|
||||
.Xr timegm 3
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn add_leap_seconds
|
||||
and
|
||||
.Fn sub_leap_seconds
|
||||
functions originally appeared in Sortix 1.1.
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2023 Jonas 'Sortie' Termansen.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -23,23 +23,25 @@
|
|||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
static const int DAYS_JANUARY = 31;
|
||||
static const int DAYS_FEBRUARY = 28;
|
||||
static const int DAYS_MARCH = 31;
|
||||
static const int DAYS_APRIL = 30;
|
||||
static const int DAYS_MAY = 31;
|
||||
static const int DAYS_JUNE = 30;
|
||||
static const int DAYS_JULY = 31;
|
||||
static const int DAYS_AUGUST = 31;
|
||||
static const int DAYS_SEPTEMBER = 30;
|
||||
static const int DAYS_OCTOBER = 31;
|
||||
static const int DAYS_NOVEMBER = 30;
|
||||
static const int DAYS_DECEMBER = 31;
|
||||
#define DAYS_JANUARY 31
|
||||
#define DAYS_FEBRUARY 28
|
||||
#define DAYS_MARCH 31
|
||||
#define DAYS_APRIL 30
|
||||
#define DAYS_MAY 31
|
||||
#define DAYS_JUNE 30
|
||||
#define DAYS_JULY 31
|
||||
#define DAYS_AUGUST 31
|
||||
#define DAYS_SEPTEMBER 30
|
||||
#define DAYS_OCTOBER 31
|
||||
#define DAYS_NOVEMBER 30
|
||||
#define DAYS_DECEMBER 31
|
||||
|
||||
#define UNKNOWN 127
|
||||
|
||||
#define DECL_LEAP_SECOND(year, jun, dec) \
|
||||
{0, 0, 0, 0, 0, jun, 0, 0, 0, 0, 0, dec}
|
||||
|
||||
static int8_t leap_seconds[][12] =
|
||||
static const char leap_seconds[][12] =
|
||||
{
|
||||
DECL_LEAP_SECOND(1970, 0, 0),
|
||||
DECL_LEAP_SECOND(1971, 0, 0),
|
||||
|
@ -88,18 +90,47 @@ static int8_t leap_seconds[][12] =
|
|||
DECL_LEAP_SECOND(2014, 0, 0),
|
||||
DECL_LEAP_SECOND(2015, 1, 0),
|
||||
DECL_LEAP_SECOND(2016, 0, 1),
|
||||
DECL_LEAP_SECOND(2017, 0, 0),
|
||||
DECL_LEAP_SECOND(2018, 0, 0),
|
||||
DECL_LEAP_SECOND(2019, 0, 0),
|
||||
DECL_LEAP_SECOND(2020, 0, 0),
|
||||
DECL_LEAP_SECOND(2021, 0, 0),
|
||||
DECL_LEAP_SECOND(2022, 0, 0),
|
||||
DECL_LEAP_SECOND(2023, 0, UNKNOWN),
|
||||
};
|
||||
|
||||
static time_t get_leap_second(int year, int month)
|
||||
static const char month_days_list[12] =
|
||||
{
|
||||
DAYS_JANUARY,
|
||||
DAYS_FEBRUARY,
|
||||
DAYS_MARCH,
|
||||
DAYS_APRIL,
|
||||
DAYS_MAY,
|
||||
DAYS_JUNE,
|
||||
DAYS_JULY,
|
||||
DAYS_AUGUST,
|
||||
DAYS_SEPTEMBER,
|
||||
DAYS_OCTOBER,
|
||||
DAYS_NOVEMBER,
|
||||
DAYS_DECEMBER,
|
||||
};
|
||||
|
||||
static time_t get_leap_second_maybe(int year, int month)
|
||||
{
|
||||
const time_t num_years = sizeof(leap_seconds) / sizeof(leap_seconds[0]);
|
||||
if ( year < 1970 )
|
||||
return 0;
|
||||
if ( num_years <= year-1970 )
|
||||
return 0;
|
||||
return UNKNOWN;
|
||||
return leap_seconds[year-1970][month];
|
||||
}
|
||||
|
||||
static time_t get_leap_second(int year, int month)
|
||||
{
|
||||
time_t result = get_leap_second_maybe(year, month);
|
||||
return result == UNKNOWN ? 0 : result;
|
||||
}
|
||||
|
||||
static time_t leap_seconds_in_year(int year)
|
||||
{
|
||||
time_t ret = 0;
|
||||
|
@ -129,6 +160,11 @@ static time_t days_in_year(int year)
|
|||
DAYS_DECEMBER;
|
||||
}
|
||||
|
||||
static int days_in_month(int year, int month)
|
||||
{
|
||||
return month_days_list[month] + (month == 1 && is_leap_year(year));
|
||||
}
|
||||
|
||||
struct tm* gmtime_r(const time_t* time_ptr, struct tm* ret)
|
||||
{
|
||||
time_t left = *time_ptr;
|
||||
|
@ -165,29 +201,13 @@ struct tm* gmtime_r(const time_t* time_ptr, struct tm* ret)
|
|||
ret->tm_wday = (ret->tm_wday - year_days + 7*7*7*7) % 7;
|
||||
}
|
||||
|
||||
int month_days_list[12] =
|
||||
{
|
||||
DAYS_JANUARY,
|
||||
DAYS_FEBRUARY + (is_leap_year(ret->tm_year) ? 1 : 0),
|
||||
DAYS_MARCH,
|
||||
DAYS_APRIL,
|
||||
DAYS_MAY,
|
||||
DAYS_JUNE,
|
||||
DAYS_JULY,
|
||||
DAYS_AUGUST,
|
||||
DAYS_SEPTEMBER,
|
||||
DAYS_OCTOBER,
|
||||
DAYS_NOVEMBER,
|
||||
DAYS_DECEMBER,
|
||||
};
|
||||
|
||||
// Figure out the correct month.
|
||||
ret->tm_mon = 0;
|
||||
ret->tm_yday = 0;
|
||||
while ( true )
|
||||
{
|
||||
int month_leaps = get_leap_second(ret->tm_year, ret->tm_mon);
|
||||
int month_days = month_days_list[ret->tm_mon];
|
||||
int month_days = days_in_month(ret->tm_year, ret->tm_mon);
|
||||
int month_seconds = month_days * 24 * 60 * 60 + month_leaps;
|
||||
if ( month_seconds <= left )
|
||||
{
|
||||
|
@ -204,7 +224,7 @@ struct tm* gmtime_r(const time_t* time_ptr, struct tm* ret)
|
|||
left = left % (24 * 60 * 60);
|
||||
|
||||
// If this is a regular timestamp.
|
||||
if ( ret->tm_mday < month_days_list[ret->tm_mon] )
|
||||
if ( ret->tm_mday < days_in_month(ret->tm_year, ret->tm_mon) )
|
||||
{
|
||||
ret->tm_yday += ret->tm_mday;
|
||||
|
||||
|
@ -257,26 +277,10 @@ time_t timegm(struct tm* tm)
|
|||
ret += year_seconds;
|
||||
}
|
||||
|
||||
int month_days_list[12] =
|
||||
{
|
||||
DAYS_JANUARY,
|
||||
DAYS_FEBRUARY + (is_leap_year(year) ? 1 : 0),
|
||||
DAYS_MARCH,
|
||||
DAYS_APRIL,
|
||||
DAYS_MAY,
|
||||
DAYS_JUNE,
|
||||
DAYS_JULY,
|
||||
DAYS_AUGUST,
|
||||
DAYS_SEPTEMBER,
|
||||
DAYS_OCTOBER,
|
||||
DAYS_NOVEMBER,
|
||||
DAYS_DECEMBER,
|
||||
};
|
||||
|
||||
for ( uint8_t m = 0; m < month; m++ )
|
||||
for ( int m = 0; m < month; m++ )
|
||||
{
|
||||
int month_leaps = get_leap_second(year, m);
|
||||
int month_days = month_days_list[m];
|
||||
int month_days = days_in_month(year, m);
|
||||
int month_seconds = month_days * 24 * 60 * 60 + month_leaps;
|
||||
ret += month_seconds;
|
||||
}
|
||||
|
@ -290,3 +294,58 @@ time_t timegm(struct tm* tm)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sub_leap_seconds(time_t* ptr)
|
||||
{
|
||||
time_t t = *ptr;
|
||||
time_t next = 0;
|
||||
time_t offset = 0;
|
||||
for ( int year = 1970; true; year++ )
|
||||
{
|
||||
for ( int month = 0; month < 12; month++ )
|
||||
{
|
||||
time_t seconds = days_in_month(year, month) * 24 * 60 * 60;
|
||||
time_t leap = get_leap_second_maybe(year, month);
|
||||
next += seconds;
|
||||
if ( leap == UNKNOWN )
|
||||
{
|
||||
*ptr = t - offset;
|
||||
return t < next - 1 ? 1 : -1;
|
||||
}
|
||||
next += leap;
|
||||
if ( t < next )
|
||||
{
|
||||
*ptr = t - offset;
|
||||
return 0 < leap && t + 1 == next ? 0 : 1;
|
||||
}
|
||||
offset += leap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int add_leap_seconds(time_t* ptr)
|
||||
{
|
||||
time_t t = *ptr;
|
||||
time_t next = 0;
|
||||
time_t offset = 0;
|
||||
for ( int year = 1970; true; year++ )
|
||||
{
|
||||
for ( int month = 0; month < 12; month++ )
|
||||
{
|
||||
time_t seconds = days_in_month(year, month) * 24 * 60 * 60;
|
||||
time_t leap = get_leap_second_maybe(year, month);
|
||||
next += seconds;
|
||||
if ( leap == UNKNOWN )
|
||||
{
|
||||
*ptr = t + offset;
|
||||
return t < next - 1 ? 1 : -1;
|
||||
}
|
||||
if ( t < next )
|
||||
{
|
||||
*ptr = t + offset;
|
||||
return leap < 0 && t + 1 == next ? 0 : 1;
|
||||
}
|
||||
offset += leap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_leap_seconds.3
|
|
@ -127,9 +127,9 @@ diff -Paur --no-dereference -- nginx.upstream/auto/install nginx/auto/install
|
|||
+
|
||||
+ mkdir -p '\$(DESTDIR)$NGX_SYSCONFDIR/default/passwd.d'
|
||||
+ mkdir -p '\$(DESTDIR)$NGX_SYSCONFDIR/default/group.d'
|
||||
+ echo "_nginx:x:100:100:_nginx:/var/empty:sh" \\
|
||||
+ echo "_nginx:x:101:101:_nginx:/var/empty:sh" \\
|
||||
+ > '\$(DESTDIR)$NGX_SYSCONFDIR/default/passwd.d/nginx'
|
||||
+ echo "_nginx::100:_nginx" \\
|
||||
+ echo "_nginx::101:_nginx" \\
|
||||
+ > '\$(DESTDIR)$NGX_SYSCONFDIR/default/group.d/nginx'
|
||||
END
|
||||
|
||||
|
|
|
@ -80,9 +80,9 @@ diff -Paur --no-dereference -- ntpd.upstream/Makefile.in ntpd/Makefile.in
|
|||
+ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default"
|
||||
+ $(INSTALL) -m 644 "$(srcdir)/ntpd.conf" "$(DESTDIR)$(sysconfdir)/default/ntpd.conf"
|
||||
+ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default/passwd.d"
|
||||
+ echo "_ntp:x:101:101:_ntp:/var/empty:sh" > "$(DESTDIR)$(sysconfdir)/default/passwd.d/ntpd"
|
||||
+ echo "_ntp:x:100:100:_ntp:/var/empty:sh" > "$(DESTDIR)$(sysconfdir)/default/passwd.d/ntpd"
|
||||
+ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)/default/group.d"
|
||||
+ echo "_ntp::101:_ntp" > "$(DESTDIR)$(sysconfdir)/default/group.d/ntpd"
|
||||
+ echo "_ntp::100:_ntp" > "$(DESTDIR)$(sysconfdir)/default/group.d/ntpd"
|
||||
|
||||
uninstall-local:
|
||||
- @if cmp -s "$(DESTDIR)$(sysconfdir)/ntpd.conf" "$(srcdir)/ntpd.conf"; then \
|
||||
|
@ -134,7 +134,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/client.c ntpd/src/client.c
|
|||
interval = error_interval();
|
||||
set_next(p, interval);
|
||||
- log_info("reply from %s: negative delay %fs, "
|
||||
+ log_info("reply from %s: negative delay %llims, "
|
||||
+ log_info("reply from %s: negative delay %lldms, "
|
||||
"next query %llds",
|
||||
log_sockaddr((struct sockaddr *)&p->addr->ss),
|
||||
- p->reply[p->shift].delay, (long long)interval);
|
||||
|
@ -148,7 +148,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/client.c ntpd/src/client.c
|
|||
interval = scale_interval(INTERVAL_QUERY_NORMAL);
|
||||
|
||||
- log_debug("reply from %s: offset %f delay %f, "
|
||||
+ log_debug("reply from %s: offset %llims delay %llims, "
|
||||
+ log_debug("reply from %s: offset %lldms delay %lldms, "
|
||||
"next query %llds",
|
||||
log_sockaddr((struct sockaddr *)&p->addr->ss),
|
||||
- offset, delay,
|
||||
|
@ -198,13 +198,27 @@ diff -Paur --no-dereference -- ntpd.upstream/src/constraint.c ntpd/src/constrain
|
|||
gettime_from_timeval(&tv[1]);
|
||||
|
||||
- log_info("constraint reply from %s: offset %f",
|
||||
+ log_info("constraint reply from %s: offset %lli ms",
|
||||
+ log_info("constraint reply from %s: offset %lld ms",
|
||||
log_sockaddr((struct sockaddr *)&cstr->addr->ss),
|
||||
- offset);
|
||||
+ (long long)(offset * 1000));
|
||||
|
||||
cstr->state = STATE_REPLY_RECEIVED;
|
||||
cstr->last = getmonotime();
|
||||
@@ -1095,6 +1100,13 @@
|
||||
/* Return parsed date as local time */
|
||||
t = timegm(&httpsdate->tls_tm);
|
||||
|
||||
+ /* PATCH: Adjust for leap seconds in Sortix CLOCK_REALTIME. */
|
||||
+#ifdef CLOCK_REALTIME_HAS_LEAP_SECONDS
|
||||
+ if (!sub_leap_seconds(&t) || !sub_leap_seconds(&when.tv_sec)) {
|
||||
+ return (NULL); /* Ignore during added leap second. */
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
/* Report parsed Date: as "received time" */
|
||||
rectv->tv_sec = t;
|
||||
rectv->tv_usec = 0;
|
||||
diff -Paur --no-dereference -- ntpd.upstream/src/control.c ntpd/src/control.c
|
||||
--- ntpd.upstream/src/control.c
|
||||
+++ ntpd/src/control.c
|
||||
|
@ -233,10 +247,8 @@ diff -Paur --no-dereference -- ntpd.upstream/src/control.c ntpd/src/control.c
|
|||
diff -Paur --no-dereference -- ntpd.upstream/src/init/ntpd ntpd/src/init/ntpd
|
||||
--- ntpd.upstream/src/init/ntpd
|
||||
+++ ntpd/src/init/ntpd
|
||||
@@ -0,0 +1,4 @@
|
||||
@@ -0,0 +1,2 @@
|
||||
+require network
|
||||
+#program=ntpd
|
||||
+#exec $program -d
|
||||
+exec ntpd -d
|
||||
diff -Paur --no-dereference -- ntpd.upstream/src/Makefile.in ntpd/src/Makefile.in
|
||||
--- ntpd.upstream/src/Makefile.in
|
||||
|
@ -336,7 +348,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntp.c ntpd/src/ntp.c
|
|||
diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
||||
--- ntpd.upstream/src/ntpd.c
|
||||
+++ ntpd/src/ntpd.c
|
||||
@@ -45,6 +45,107 @@
|
||||
@@ -45,6 +45,53 @@
|
||||
|
||||
#include "ntpd.h"
|
||||
|
||||
|
@ -364,60 +376,6 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+From musl:
|
||||
+
|
||||
+Copyright © 2005-2014 Rich Felker, et al.
|
||||
+
|
||||
+Permission is hereby granted, free of charge, to any person obtaining
|
||||
+a copy of this software and associated documentation files (the
|
||||
+"Software"), to deal in the Software without restriction, including
|
||||
+without limitation the rights to use, copy, modify, merge, publish,
|
||||
+distribute, sublicense, and/or sell copies of the Software, and to
|
||||
+permit persons to whom the Software is furnished to do so, subject to
|
||||
+the following conditions:
|
||||
+
|
||||
+The above copyright notice and this permission notice shall be
|
||||
+included in all copies or substantial portions of the Software.
|
||||
+
|
||||
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
+*/
|
||||
+int daemon(int nochdir, int noclose)
|
||||
+{
|
||||
+ if (!nochdir && chdir("/"))
|
||||
+ return -1;
|
||||
+ if (!noclose) {
|
||||
+ int fd, failed = 0;
|
||||
+ if ((fd = open("/dev/null", O_RDWR)) < 0) return -1;
|
||||
+ if (dup2(fd, 0) < 0 || dup2(fd, 1) < 0 || dup2(fd, 2) < 0)
|
||||
+ failed++;
|
||||
+ if (fd > 2) close(fd);
|
||||
+ if (failed) return -1;
|
||||
+ }
|
||||
+
|
||||
+ switch(fork()) {
|
||||
+ case 0: break;
|
||||
+ case -1: return -1;
|
||||
+ default: _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ if (setsid() < 0) return -1;
|
||||
+
|
||||
+ switch(fork()) {
|
||||
+ case 0: break;
|
||||
+ case -1: return -1;
|
||||
+ default: _exit(0);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+adjfreq(const int64_t *freq, int64_t *oldfreq)
|
||||
+{
|
||||
|
@ -444,7 +402,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
void sighdlr(int);
|
||||
__dead void usage(void);
|
||||
int auto_preconditions(const struct ntpd_conf *);
|
||||
@@ -70,6 +171,7 @@
|
||||
@@ -70,6 +117,7 @@
|
||||
volatile sig_atomic_t sigchld = 0;
|
||||
struct imsgbuf *ibuf;
|
||||
int timeout = INFTIM;
|
||||
|
@ -452,7 +410,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
|
||||
extern u_int constraint_cnt;
|
||||
|
||||
@@ -108,6 +210,17 @@
|
||||
@@ -108,6 +156,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -470,7 +428,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
__dead void
|
||||
usage(void)
|
||||
{
|
||||
@@ -176,7 +289,10 @@
|
||||
@@ -176,7 +235,10 @@
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
|
@ -482,7 +440,7 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
|
||||
memset(&lconf, 0, sizeof(lconf));
|
||||
|
||||
@@ -222,6 +338,12 @@
|
||||
@@ -222,6 +284,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,34 +453,63 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
/* log to stderr until daemonized */
|
||||
logdest = LOG_TO_STDERR;
|
||||
if (!lconf.debug)
|
||||
@@ -335,6 +457,10 @@
|
||||
if (pledge("stdio rpath inet settime proc exec id", NULL) == -1)
|
||||
err(1, "pledge");
|
||||
|
||||
+ if (!lconf.settime) {
|
||||
+ ready();
|
||||
+ }
|
||||
+
|
||||
while (quit == 0) {
|
||||
new_cnt = PFD_MAX + constraint_cnt;
|
||||
if (new_cnt > pfd_elms) {
|
||||
@@ -380,6 +506,7 @@
|
||||
@@ -287,11 +355,13 @@
|
||||
logdest = lconf.debug ? LOG_TO_STDERR : LOG_TO_SYSLOG;
|
||||
if (!lconf.settime) {
|
||||
log_init(logdest, lconf.verbose, LOG_DAEMON);
|
||||
+#if 0 /* PATCH: Modern daemons must not background. */
|
||||
if (!lconf.debug) {
|
||||
if (daemon(1, 0))
|
||||
fatal("daemon");
|
||||
writepid(&lconf);
|
||||
}
|
||||
+#endif
|
||||
} else {
|
||||
settime_deadline = getmonotime();
|
||||
timeout = 100;
|
||||
@@ -375,11 +445,14 @@
|
||||
log_init(logdest, lconf.verbose, LOG_DAEMON);
|
||||
log_warnx("no reply received in time, skipping initial "
|
||||
"time setting");
|
||||
+#if 0
|
||||
if (!lconf.debug) {
|
||||
if (daemon(1, 0))
|
||||
fatal("daemon");
|
||||
writepid(&lconf);
|
||||
}
|
||||
+#endif
|
||||
+ ready();
|
||||
}
|
||||
|
||||
if (nfds > 0 && (pfd[PFD_PIPE].revents & POLLOUT))
|
||||
@@ -487,6 +614,7 @@
|
||||
@@ -473,20 +546,25 @@
|
||||
case IMSG_SETTIME:
|
||||
if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(d))
|
||||
fatalx("invalid IMSG_SETTIME received");
|
||||
- if (!lconf->settime)
|
||||
+ if (!lconf->settime) {
|
||||
+ ready();
|
||||
break;
|
||||
+ }
|
||||
log_init(lconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG,
|
||||
lconf->verbose, LOG_DAEMON);
|
||||
memcpy(&d, imsg.data, sizeof(d));
|
||||
ntpd_settime(d);
|
||||
+#if 0
|
||||
/* daemonize now */
|
||||
if (!lconf->debug) {
|
||||
if (daemon(1, 0))
|
||||
fatal("daemon");
|
||||
writepid(lconf);
|
||||
}
|
||||
+#endif
|
||||
lconf->settime = 0;
|
||||
timeout = INFTIM;
|
||||
+ ready();
|
||||
break;
|
||||
case IMSG_CONSTRAINT_QUERY:
|
||||
priv_constraint_msg(imsg.hdr.peerid,
|
||||
@@ -507,9 +635,8 @@
|
||||
@@ -507,9 +585,8 @@
|
||||
void
|
||||
reset_adjtime(void)
|
||||
{
|
||||
|
@ -533,25 +520,52 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
if (adjtime(&tv, NULL) == -1)
|
||||
log_warn("reset adjtime failed");
|
||||
}
|
||||
@@ -523,9 +650,9 @@
|
||||
@@ -523,9 +600,9 @@
|
||||
|
||||
d += getoffset();
|
||||
if (d >= threshold || d <= -1 * threshold)
|
||||
- log_info("adjusting local clock by %fs", d);
|
||||
+ log_info("adjusting local clock by %llims", (long long)(d * 1000));
|
||||
+ log_info("adjusting local clock by %lldms", (long long)(d * 1000));
|
||||
else
|
||||
- log_debug("adjusting local clock by %fs", d);
|
||||
+ log_debug("adjusting local clock by %llims", (long long)(d * 1000));
|
||||
+ log_debug("adjusting local clock by %lldms", (long long)(d * 1000));
|
||||
|
||||
#ifdef HAVE_ADJTIMEX
|
||||
int rc;
|
||||
@@ -614,14 +741,26 @@
|
||||
@@ -582,12 +659,12 @@
|
||||
if (wrlog) {
|
||||
if (ppmfreq >= LOG_NEGLIGIBLE_ADJFREQ ||
|
||||
ppmfreq <= -LOG_NEGLIGIBLE_ADJFREQ)
|
||||
- log_info("adjusting clock frequency by %f to %fppm%s",
|
||||
- ppmfreq, curfreq / 1e3 / (1LL << 32),
|
||||
+ log_info("adjusting clock frequency by %lld to %lldppm%s",
|
||||
+ (long long)ppmfreq, (long long)(curfreq / 1e3 / (1LL << 32)),
|
||||
r ? "" : " (no drift file)");
|
||||
else
|
||||
- log_debug("adjusting clock frequency by %f to %fppm%s",
|
||||
- ppmfreq, curfreq / 1e3 / (1LL << 32),
|
||||
+ log_debug("adjusting clock frequency by %lld to %lldppm%s",
|
||||
+ (long long)ppmfreq, (long long)(curfreq / 1e3 / (1LL << 32)),
|
||||
r ? "" : " (no drift file)");
|
||||
}
|
||||
|
||||
@@ -610,18 +687,36 @@
|
||||
return;
|
||||
}
|
||||
d_to_tv(d, &tv);
|
||||
+#ifdef CLOCK_REALTIME_HAS_LEAP_SECONDS
|
||||
+ if (!add_leap_seconds(&tv.tv_sec)) {
|
||||
+ /* You finally, really did it. You maniacs! You blew it up! God damn
|
||||
+ you. God damn you all to hell. */
|
||||
+ return; /* Removed leap seconds have no representation here. */
|
||||
+ }
|
||||
+#endif
|
||||
curtime.tv_usec += tv.tv_usec + 1000000;
|
||||
curtime.tv_sec += tv.tv_sec - 1 + (curtime.tv_usec / 1000000);
|
||||
curtime.tv_usec %= 1000000;
|
||||
|
||||
+#if defined(__sortix__)
|
||||
+ struct timespec ts =
|
||||
+ {
|
||||
+ struct timespec ts = {
|
||||
+ .tv_sec = curtime.tv_sec,
|
||||
+ .tv_nsec = curtime.tv_usec * 1000
|
||||
+ };
|
||||
|
@ -569,38 +583,60 @@ diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.c ntpd/src/ntpd.c
|
|||
strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y",
|
||||
localtime(&tval));
|
||||
- log_info("set local clock to %s (offset %fs)", buf, d);
|
||||
+ log_info("set local clock to %s (offset %llims)", buf, (long long)(d * 1000.0));
|
||||
+ log_info("set local clock to %s (offset %lldms)", buf, (long long)(d * 1000.0));
|
||||
}
|
||||
|
||||
static FILE *freqfp;
|
||||
@@ -632,6 +771,7 @@
|
||||
@@ -632,6 +727,7 @@
|
||||
int64_t current;
|
||||
int fd;
|
||||
double d;
|
||||
+ long long lli;
|
||||
+ long long lld;
|
||||
|
||||
fd = open(DRIFTFILE, O_RDWR);
|
||||
if (fd == -1) {
|
||||
@@ -649,7 +789,8 @@
|
||||
@@ -649,7 +745,8 @@
|
||||
if (adjfreq(NULL, ¤t) == -1)
|
||||
log_warn("adjfreq failed");
|
||||
else if (current == 0 && freqfp) {
|
||||
- if (fscanf(freqfp, "%lf", &d) == 1) {
|
||||
+ if (fscanf(freqfp, "%lli", &lli) == 1) {
|
||||
+ d = (double)lli;
|
||||
+ if (fscanf(freqfp, "%lld", &lld) == 1) {
|
||||
+ d = (double)lld;
|
||||
d /= 1e6; /* scale from ppm */
|
||||
ntpd_adjfreq(d, 0);
|
||||
} else
|
||||
@@ -667,7 +808,8 @@
|
||||
@@ -667,7 +764,8 @@
|
||||
if (freqfp == NULL)
|
||||
return 0;
|
||||
rewind(freqfp);
|
||||
- r = fprintf(freqfp, "%.3f\n", d * 1e6); /* scale to ppm */
|
||||
+ long long lli = (long long)(d * 1e6);
|
||||
+ r = fprintf(freqfp, "%lli\n", lli); /* scale to ppm */
|
||||
+ long long lld = (long long)(d * 1e6);
|
||||
+ r = fprintf(freqfp, "%lld\n", lld); /* scale to ppm */
|
||||
if (r < 0 || fflush(freqfp) != 0) {
|
||||
if (warnonce) {
|
||||
log_warnx("can't write %s", DRIFTFILE);
|
||||
@@ -901,8 +999,8 @@
|
||||
clock_offset = cstatus->clock_offset < 0 ?
|
||||
-1.0 * cstatus->clock_offset : cstatus->clock_offset;
|
||||
if (clock_offset > 5e-7)
|
||||
- printf(", clock offset is %.3fms\n",
|
||||
- cstatus->clock_offset);
|
||||
+ printf(", clock offset is %lldms\n",
|
||||
+ (long long)cstatus->clock_offset);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
@@ -952,8 +1050,8 @@
|
||||
(long long)cpeer->next, (long long)cpeer->poll);
|
||||
|
||||
if (cpeer->trustlevel >= TRUSTLEVEL_BADPEER)
|
||||
- printf(" %12.3fms %9.3fms %8.3fms\n", cpeer->offset,
|
||||
- cpeer->delay, cpeer->jitter);
|
||||
+ printf(" %12lldms %9lldms %8lldms\n", (long long)cpeer->offset,
|
||||
+ (long long)cpeer->delay, (long long)cpeer->jitter);
|
||||
else
|
||||
printf(" ---- peer not valid ----\n");
|
||||
|
||||
diff -Paur --no-dereference -- ntpd.upstream/src/ntpd.h ntpd/src/ntpd.h
|
||||
--- ntpd.upstream/src/ntpd.h
|
||||
+++ ntpd/src/ntpd.h
|
||||
|
@ -794,12 +830,21 @@ diff -Paur --no-dereference -- ntpd.upstream/src/util.c ntpd/src/util.c
|
|||
double
|
||||
gettime_corrected(void)
|
||||
{
|
||||
diff -Paur --no-dereference -- ntpd.upstream/TODO.sortix ntpd/TODO.sortix
|
||||
--- ntpd.upstream/TODO.sortix
|
||||
+++ ntpd/TODO.sortix
|
||||
@@ -0,0 +1,5 @@
|
||||
+- nptd is unaware of leap seconds but Sortix is aware of them to the clock doesn't actually get synced correctly.
|
||||
+- Sortix needs `adjtime` or the time adjustments can be jarring.
|
||||
+- Sortix needs `strptime`.
|
||||
+- Sortix needs `getservbyname` but worked around by hard-coding the ntp port.
|
||||
+- The dns process wasn't being properly killed and awaited when exiting.
|
||||
@@ -48,6 +50,17 @@
|
||||
if (gettimeofday(&tv, NULL) == -1)
|
||||
fatal("gettimeofday");
|
||||
|
||||
+/* PATCH: Sortix counts leap seconds in CLOCK_REALTIME but ntpd doesn't measure
|
||||
+ leap seconds. Subtract them from the internal time to be UTC. */
|
||||
+#ifdef CLOCK_REALTIME_HAS_LEAP_SECONDS
|
||||
+ while (!sub_leap_seconds(&tv.tv_sec)) {
|
||||
+ /* UTC cannot represent the current second because a leap second is
|
||||
+ being inserted right now. Wait for it to pass and ignore it. */
|
||||
+ sleep(1);
|
||||
+ gettimeofday(&tv, NULL);
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
return (gettime_from_timeval(&tv));
|
||||
}
|
||||
|
||||
|
|
|
@ -9,5 +9,4 @@ UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/OpenNTPD
|
|||
UPSTREAM_ARCHIVE=$ARCHIVE
|
||||
BUILD_SYSTEM=configure
|
||||
MAKE_VARS='V=1'
|
||||
POST_INSTALL=tix-eradicate-libtool-la
|
||||
VERSION_REGEX='([0-9]+\.[0-9]+p[0-9]+)'
|
||||
|
|
|
@ -271,6 +271,17 @@ and such.
|
|||
.Dv CLOCK_REALTIME
|
||||
counts the number of seconds since the epoch including leap seconds, unlike
|
||||
other operating systems and in violation of POSIX.
|
||||
.Dv CLOCK_REALTIME_HAS_LEAP_SECONDS
|
||||
definition advertises
|
||||
.Dv CLOCK_REALTIME
|
||||
contains leap seconds since the epoch in the TAI-10 format.
|
||||
.Pp
|
||||
.Xr sub_leap_seconds 3
|
||||
converts timestamps from TAI-10 to UTC by subtracting the leap seconds, while
|
||||
.Xr add_leap_seconds 3
|
||||
converts timestamps from UTC TO TAI-10 by adding the leap seconds.
|
||||
These functions are useful when communicating with other operating systems
|
||||
either via the network or exchanged data files.
|
||||
.Ss u_char, u_short, u_int, u_long
|
||||
.Vt unsigned char ,
|
||||
.Vt unsigned short ,
|
||||
|
|
55
utils/date.c
55
utils/date.c
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2021 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2013, 2021, 2023 Jonas 'Sortie' Termansen.
|
||||
* Copyright (c) 2022 Juhani 'nortti' Krekelä.
|
||||
* Copyright (c) 2022 Dennis Wölfing.
|
||||
*
|
||||
|
@ -19,6 +19,8 @@
|
|||
* Print or set system date and time.
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <err.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
@ -50,13 +52,18 @@ static char* astrftime(const char* format, const struct tm* tm)
|
|||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
const char* format = "+%a %b %e %H:%M:%S %Z %Y";
|
||||
const char* date = NULL;
|
||||
bool set = false;
|
||||
const char* reference = NULL;
|
||||
|
||||
int opt;
|
||||
while ( (opt = getopt(argc, argv, "u")) != -1 )
|
||||
while ( (opt = getopt(argc, argv, "d:r:s:u")) != -1 )
|
||||
{
|
||||
switch ( opt )
|
||||
{
|
||||
case 'd': date = optarg; break;
|
||||
case 'r': reference = optarg; break;
|
||||
case 's': date = optarg; set = true; break;
|
||||
case 'u':
|
||||
if ( setenv("TZ", "UTC0", 1) )
|
||||
err(1, "setenv");
|
||||
|
@ -65,20 +72,52 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
}
|
||||
|
||||
if ( date && reference )
|
||||
errx(1, "the -d and -r options are mutually incompatible");
|
||||
if ( set && reference )
|
||||
errx(1, "the -s and -r options are mutually incompatible");
|
||||
|
||||
const char* format = "+%a %b %e %H:%M:%S %Z %Y";
|
||||
if ( 1 <= argc - optind )
|
||||
{
|
||||
if ( argv[optind][0] != '+' )
|
||||
errx(1, "setting the system time is not implemented");
|
||||
errx(1, "the format specifier must start with a +");
|
||||
format = argv[optind];
|
||||
}
|
||||
if ( 2 <= argc - optind )
|
||||
errx(1, "unexpected extra operand: %s", argv[optind + 1]);
|
||||
|
||||
time_t current_time = time(NULL);
|
||||
struct timespec moment = {0};
|
||||
struct tm tm = {0};
|
||||
|
||||
struct tm tm;
|
||||
if ( !localtime_r(¤t_time, &tm) )
|
||||
err(1, "localtime_r(%ji)", (intmax_t) current_time);
|
||||
if ( date )
|
||||
{
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
if ( !strptime(date, format + 1, &tm) )
|
||||
errx(1, "date didn't match %s: %s", format + 1, date);
|
||||
moment.tv_sec = timegm(&tm); // TODO: timelocal
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( reference )
|
||||
{
|
||||
struct stat st;
|
||||
if ( stat(reference, &st) < 0 )
|
||||
err(1, "%s", reference);
|
||||
moment = st.st_mtim;
|
||||
}
|
||||
else
|
||||
clock_gettime(CLOCK_REALTIME, &moment);
|
||||
if ( !localtime_r(&moment.tv_sec, &tm) )
|
||||
err(1, "localtime_r(%ji)", (intmax_t) moment.tv_sec);
|
||||
}
|
||||
|
||||
if ( set )
|
||||
{
|
||||
if ( clock_settime(CLOCK_REALTIME, &moment) < 0 )
|
||||
err(1, "clock_settime: CLOCK_REALTIME");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* string = astrftime(format, &tm);
|
||||
if ( !string )
|
||||
|
|
Loading…
Reference in New Issue