You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 lines
3.2 KiB

// 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
}