// tera-hwd is the minimal privileged hardware adapter for TERA board controls. package main import ( "errors" "log" "net" "os" "os/signal" "path/filepath" "syscall" "tera-clone/services/tera-api/internal/hardware/greenled" "tera-clone/services/tera-api/internal/hardware/greenledsocket" "tera-clone/services/tera-api/internal/hardware/systemcontrol" ) func main() { greenSocketPath := getenv("TERA_HWD_GREEN_LED_SOCKET", greenledsocket.DefaultSocketPath) systemSocketPath := getenv("TERA_HWD_SYSTEM_SOCKET", systemcontrol.DefaultSocketPath) sysfsRoot := getenv("TERA_HWD_GREEN_LED_SYSFS_ROOT", greenled.DefaultSysfsRoot) resetButtonPath := getenv("TERA_HWD_RESET_BUTTON_VALUE_PATH", "/sys/class/gpio/manual_KeyReset/value") greenListener, err := listen(greenSocketPath, "TERA_HWD_GREEN_LED_SOCKET") if err != nil { log.Fatalf("tera-hwd green LED socket setup failed: %v", err) } systemListener, err := listen(systemSocketPath, "TERA_HWD_SYSTEM_SOCKET") if err != nil { _ = greenListener.Close() _ = os.Remove(greenSocketPath) log.Fatalf("tera-hwd system socket setup failed: %v", err) } defer func() { _ = greenListener.Close() _ = systemListener.Close() _ = os.Remove(greenSocketPath) _ = os.Remove(systemSocketPath) }() greenServer := greenledsocket.Server{Controller: greenled.NewSysfsController(sysfsRoot)} systemServer := systemcontrol.Server{ Controller: systemcontrol.CommandController{RebootCommand: "/sbin/reboot"}, ResetButton: systemcontrol.SysfsResetButton{ValuePath: resetButtonPath, ActiveLow: true}, } done := make(chan error, 2) go func() { done <- greenServer.Serve(greenListener) }() go func() { done <- systemServer.Serve(systemListener) }() log.Printf("tera-hwd serving green LED control on %s and system control on %s", greenSocketPath, systemSocketPath) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) remaining := 2 select { case signal := <-signals: log.Printf("tera-hwd stopping after %s", signal) case err := <-done: remaining-- if err != nil { log.Printf("tera-hwd service failed: %v", err) } } _ = greenListener.Close() _ = systemListener.Close() for remaining > 0 { if err := <-done; err != nil { log.Printf("tera-hwd stop error: %v", err) } remaining-- } } func listen(socketPath, variable string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New(variable + " 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 hardware 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 }