mirror of https://github.com/jetkvm/kvm.git
106 lines
2.1 KiB
Go
106 lines
2.1 KiB
Go
//go:build linux
|
|
|
|
package timesync
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func TimetoRtcTime(t time.Time) unix.RTCTime {
|
|
return unix.RTCTime{
|
|
Sec: int32(t.Second()),
|
|
Min: int32(t.Minute()),
|
|
Hour: int32(t.Hour()),
|
|
Mday: int32(t.Day()),
|
|
Mon: int32(t.Month() - 1),
|
|
Year: int32(t.Year() - 1900),
|
|
Wday: int32(0),
|
|
Yday: int32(0),
|
|
Isdst: int32(0),
|
|
}
|
|
}
|
|
|
|
func RtcTimetoTime(t unix.RTCTime) time.Time {
|
|
return time.Date(
|
|
int(t.Year)+1900,
|
|
time.Month(t.Mon+1),
|
|
int(t.Mday),
|
|
int(t.Hour),
|
|
int(t.Min),
|
|
int(t.Sec),
|
|
0,
|
|
time.UTC,
|
|
)
|
|
}
|
|
|
|
func (t *TimeSync) getRtcDevice() (*os.File, error) {
|
|
if t.rtcDevice == nil {
|
|
file, err := os.OpenFile(t.rtcDevicePath, os.O_RDWR, 0666)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
t.rtcDevice = file
|
|
}
|
|
return t.rtcDevice, nil
|
|
}
|
|
|
|
func (t *TimeSync) getRtcDeviceFd() (int, error) {
|
|
device, err := t.getRtcDevice()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return int(device.Fd()), nil
|
|
}
|
|
|
|
// Read implements Read for the Linux RTC
|
|
func (t *TimeSync) readRtcTime() (time.Time, error) {
|
|
fd, err := t.getRtcDeviceFd()
|
|
if err != nil {
|
|
return time.Time{}, fmt.Errorf("failed to get RTC device fd: %w", err)
|
|
}
|
|
|
|
rtcTime, err := unix.IoctlGetRTCTime(fd)
|
|
if err != nil {
|
|
return time.Time{}, fmt.Errorf("failed to get RTC time: %w", err)
|
|
}
|
|
|
|
date := RtcTimetoTime(*rtcTime)
|
|
|
|
return date, nil
|
|
}
|
|
|
|
// Set implements Set for the Linux RTC
|
|
// ...
|
|
// It might be not accurate as the time consumed by the system call is not taken into account
|
|
// but it's good enough for our purposes
|
|
func (t *TimeSync) setRtcTime(tu time.Time) error {
|
|
rt := TimetoRtcTime(tu)
|
|
|
|
fd, err := t.getRtcDeviceFd()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get RTC device fd: %w", err)
|
|
}
|
|
|
|
currentRtcTime, err := t.readRtcTime()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read RTC time: %w", err)
|
|
}
|
|
|
|
t.l.Info().
|
|
Interface("rtc_time", tu).
|
|
Str("offset", tu.Sub(currentRtcTime).String()).
|
|
Msg("set rtc time")
|
|
|
|
if err := unix.IoctlSetRTCTime(fd, &rt); err != nil {
|
|
return fmt.Errorf("failed to set RTC time: %w", err)
|
|
}
|
|
|
|
metricRTCUpdateCount.Inc()
|
|
|
|
return nil
|
|
}
|