// tera-timed is the minimal privileged system clock and timezone adapter. package main import ( "errors" "log" "net" "os" "os/signal" "path/filepath" "syscall" "tera-clone/services/tera-api/internal/systemtime" "tera-clone/services/tera-api/internal/systemtime/timesocket" ) func main() { socketPath := getenv("TERA_TIMED_SOCKET", timesocket.DefaultSocketPath) zoneinfoRoot := getenv("TERA_TIMED_ZONEINFO_ROOT", systemtime.DefaultZoneinfoRoot) localtimePath := getenv("TERA_TIMED_LOCALTIME_PATH", systemtime.DefaultLocaltimePath) applier, err := systemtime.NewOSApplier(zoneinfoRoot, localtimePath) if err != nil { log.Fatalf("tera-timed system time setup failed: %v", err) } ntpApplier, err := systemtime.NewOSNTPApplier( getenv("TERA_TIMED_NTP_CONFIG", systemtime.DefaultNTPConfigPath), getenv("TERA_TIMED_NTP_INIT", systemtime.DefaultNTPInitPath), getenv("TERA_TIMED_NTP_DAEMON", systemtime.DefaultNTPDaemonPath), ) if err != nil { log.Fatalf("tera-timed NTP setup failed: %v", err) } listener, err := listen(socketPath) if err != nil { log.Fatalf("tera-timed socket setup failed: %v", err) } defer func() { _ = listener.Close() _ = os.Remove(socketPath) }() server := timesocket.Server{Controller: systemtime.NewTransactionalController(applier, ntpApplier)} done := make(chan error, 1) go func() { done <- server.Serve(listener) }() log.Printf("tera-timed serving system time control on %s", socketPath) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) select { case signal := <-signals: log.Printf("tera-timed stopping after %s", signal) _ = listener.Close() if err := <-done; err != nil { log.Printf("tera-timed stop error: %v", err) } case err := <-done: if err != nil { log.Fatalf("tera-timed failed: %v", err) } } } func listen(socketPath string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New("TERA_TIMED_SOCKET must be an absolute path") } if err := os.MkdirAll(filepath.Dir(socketPath), 0o750); err != nil { return nil, err } if info, err := os.Lstat(socketPath); err == nil { if info.Mode()&os.ModeSocket == 0 { return nil, errors.New("refusing to replace non-socket system time control path") } if err := os.Remove(socketPath); err != nil { return nil, err } } else if !os.IsNotExist(err) { return nil, err } listener, err := net.Listen("unix", socketPath) if err != nil { return nil, err } if err := os.Chmod(socketPath, 0o660); err != nil { _ = listener.Close() return nil, err } return listener, nil } func getenv(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback }