summaryrefslogtreecommitdiff
path: root/systemd-timesyncd-wrap.go
blob: 3d5971ba1f7dcb18998fff9cc485642820cbcdf8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package main

import (
	"net"
	"os"
	"strings"
	"sync"
	"syscall"
)

func socketUnixgram(name string) (*net.UnixConn, error) {
	fd, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM|syscall.SOCK_CLOEXEC, 0)
	if err != nil {
		return nil, err
	}
	conn, err := net.FileConn(os.NewFile(uintptr(fd), name))
	if err != nil {
		return nil, err
	}
	unixConn := conn.(*net.UnixConn)
	return unixConn, nil
}

func sendmsg(dat, oob []byte, sockname string) error {
	writer, err := socketUnixgram(sockname)
	if err != nil {
		return err
	}
	_, _, err = writer.WriteMsgUnix(dat, oob, &net.UnixAddr{Net: "unixgram", Name: sockname})
	return err
}

func main() {
	sync_sockname := "/run/timesyncd/time-sync.sock"
	fake_sockname := "/run/timesyncd/notify.sock"
	real_sockname := os.Getenv("NOTIFY_SOCKET")

	fake_sock, err := net.ListenUnixgram("unixgram", &net.UnixAddr{Net: "unixgram", Name: fake_sockname})
	if err != nil {
		os.Stderr.WriteString(err.Error())
		os.Stderr.Write([]byte{'\n'})
		os.Exit(127)
	}

	os.Setenv("NOTIFY_SOCKET", fake_sockname)
	proc, err := os.StartProcess(os.Args[1], os.Args[1:], &os.ProcAttr{})
	if err != nil {
		os.Stderr.WriteString(err.Error())
		os.Stderr.Write([]byte{'\n'})
		os.Exit(127)
	}

	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		synced := false
		var dat [4096]byte
		oob := make([]byte, syscall.CmsgSpace(syscall.SizeofUcred)+syscall.CmsgSpace(8*768))
		for {
			n, oobn, flags, _, err := fake_sock.ReadMsgUnix(dat[:], oob[:])
			if err != nil {
				break
			}
			if flags&syscall.MSG_TRUNC != 0 {
				continue
			}
			if !synced {
				for _, line := range strings.Split(string(dat[:n]), "\n") {
					if strings.HasPrefix(line, "STATUS=Synchronized") {
						_ = sendmsg([]byte(line), nil, sync_sockname)
						synced = true
						break
					}
				}
			}
			_ = sendmsg(dat[:n], oob[:oobn], real_sockname)
		}
		wg.Done()
	}()

	state, err := proc.Wait()
	_ = fake_sock.Close()
	wg.Wait()

	if err != nil {
		os.Stderr.WriteString(err.Error())
		os.Stderr.Write([]byte{'\n'})
		os.Exit(127)
	}
	status := state.Sys().(syscall.WaitStatus)
	if status.Exited() {
		os.Exit(status.ExitStatus())
	}
	if status.Signaled() {
		self, _ := os.FindProcess(os.Getpid())
		self.Signal(status.Signal())
	}
}