ntp: set real-time clock (hwclock) if present

This commit is contained in:
Michael Stapelberg 2018-06-13 23:51:31 +02:00
parent 238bbfa55e
commit 6c059494af
4 changed files with 59 additions and 6 deletions

View File

@ -4,29 +4,50 @@ package main
import ( import (
"log" "log"
"math/rand" "math/rand"
"os"
"syscall" "syscall"
"time" "time"
"github.com/beevik/ntp" "github.com/beevik/ntp"
) )
func set() error { func set(rtc *os.File) error {
r, err := ntp.Query("0.gokrazy.pool.ntp.org") r, err := ntp.Query("0.gokrazy.pool.ntp.org")
if err != nil { if err != nil {
return err return err
} }
tv := syscall.NsecToTimeval(r.Time.UnixNano()) tv := syscall.NsecToTimeval(r.Time.UnixNano())
return syscall.Settimeofday(&tv) if err := syscall.Settimeofday(&tv); err != nil {
return err
}
if rtc == nil {
return nil
}
return setRTC(rtc, r.Time.UTC())
} }
func main() { func main() {
log.SetFlags(log.LstdFlags | log.Lshortfile) log.SetFlags(log.LstdFlags | log.Lshortfile)
mustDropPrivileges() var rtc *os.File
var err error
if os.Getenv("NTP_PRIVILEGES_DROPPED") == "1" {
if os.Getenv("NTP_RTC") == "1" {
rtc = os.NewFile(3, "/dev/rtc0")
}
} else {
rtc, err = os.Open("/dev/rtc0")
if err != nil && !os.IsNotExist(err) {
log.Fatal(err)
}
}
mustDropPrivileges(rtc)
for { for {
if err := set(); err != nil { if err := set(rtc); err != nil {
log.Fatalf("setting time failed: %v", err) log.Fatalf("setting time failed: %v", err)
} }
time.Sleep(1*time.Hour + time.Duration(rand.Int63n(250))*time.Millisecond) time.Sleep(1*time.Hour + time.Duration(rand.Int63n(250))*time.Millisecond)

View File

@ -46,7 +46,7 @@ func getCaps() (caps, error) {
// mustDropPrivileges executes the program in a child process, dropping root // mustDropPrivileges executes the program in a child process, dropping root
// privileges, but retaining the CAP_SYS_TIME capability to change the system // privileges, but retaining the CAP_SYS_TIME capability to change the system
// clock. // clock.
func mustDropPrivileges() { func mustDropPrivileges(rtc *os.File) {
if os.Getenv("NTP_PRIVILEGES_DROPPED") == "1" { if os.Getenv("NTP_PRIVILEGES_DROPPED") == "1" {
return return
} }
@ -71,6 +71,10 @@ func mustDropPrivileges() {
cmd := exec.Command(os.Args[0]) cmd := exec.Command(os.Args[0])
cmd.Env = append(os.Environ(), "NTP_PRIVILEGES_DROPPED=1") cmd.Env = append(os.Environ(), "NTP_PRIVILEGES_DROPPED=1")
if rtc != nil {
cmd.Env = append(cmd.Env, "NTP_RTC=1")
cmd.ExtraFiles = []*os.File{rtc}
}
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{ cmd.SysProcAttr = &syscall.SysProcAttr{

View File

@ -2,7 +2,9 @@
package main package main
import "os"
// mustDropPrivileges (on Go < 1.9) does nothing, as the AmbientCaps field in // mustDropPrivileges (on Go < 1.9) does nothing, as the AmbientCaps field in
// syscall.SysProcAttr was only introduced in Go 1.9. // syscall.SysProcAttr was only introduced in Go 1.9.
func mustDropPrivileges() { func mustDropPrivileges(*os.File) {
} }

26
cmd/ntp/rtc.go Normal file
View File

@ -0,0 +1,26 @@
package main
import (
"log"
"os"
"time"
"unsafe"
"golang.org/x/sys/unix"
)
func setRTC(rtc *os.File, now time.Time) error {
c := unix.RTCTime{
Sec: int32(now.Second()),
Min: int32(now.Minute()),
Hour: int32(now.Hour()),
Mday: int32(now.Day()),
Mon: int32(now.Month() - 1),
Year: int32(now.Year() - 1900),
}
if _, _, errno := unix.Syscall(unix.SYS_IOCTL, rtc.Fd(), unix.RTC_SET_TIME, uintptr(unsafe.Pointer(&c))); errno != 0 {
return errno
}
log.Printf("RTC set to %+v", c)
return nil
}