// tera-logd owns the authoritative userdata event journal. package main import ( "errors" "log" "net" "os" "os/signal" "path/filepath" "strconv" "syscall" "tera-clone/services/tera-api/internal/logservice" "tera-clone/services/tera-api/internal/logstorage" "tera-clone/services/tera-api/internal/storage/capacity" ) func main() { policyPath := getenv("TERA_LOGD_STORAGE_POLICY", "/userdata/storage-layout.json") policy, err := capacity.LoadPolicy(policyPath) if err != nil { log.Fatalf("tera-logd storage policy setup failed: %v", err) } store, err := logstorage.Open(logstorage.Options{ Root: getenv("TERA_LOGD_ROOT", "/userdata/log"), SegmentBytes: getenvInt64("TERA_LOGD_SEGMENT_BYTES", 4<<20), AuditCapBytes: policy.CapsBytes.AuditLogs, SystemCapBytes: policy.CapsBytes.SystemEvents, PortCapBytes: policy.CapsBytes.PortEvents, IndexCapBytes: policy.CapsBytes.StateAndIndexes, GlobalFreeFloor: policy.CapsBytes.GlobalFreeFloor, }) if err != nil { log.Fatalf("tera-logd store setup failed: %v", err) } socketPath := getenv("TERA_LOGD_SOCKET", logservice.DefaultSocketPath) listener, err := listen(socketPath) if err != nil { log.Fatalf("tera-logd socket setup failed: %v", err) } defer func() { _ = listener.Close() _ = os.Remove(socketPath) }() server := logservice.Server{Store: store} done := make(chan error, 1) go func() { done <- server.Serve(listener) }() log.Printf("tera-logd serving authoritative log storage on %s", socketPath) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) select { case signal := <-signals: log.Printf("tera-logd stopping after %s", signal) _ = listener.Close() if err := <-done; err != nil { log.Printf("tera-logd stop error: %v", err) } case err := <-done: if err != nil { log.Fatalf("tera-logd failed: %v", err) } } } func listen(socketPath string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New("TERA_LOGD_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 log service 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 } func getenvInt64(key string, fallback int64) int64 { value, err := strconv.ParseInt(os.Getenv(key), 10, 64) if err != nil || value <= 0 { return fallback } return value }