// tera-snmpd is the minimal privileged Net-SNMP configuration adapter. package main import ( "errors" "log" "net" "os" "os/signal" "path/filepath" "syscall" "tera-clone/services/tera-api/internal/snmpagent" "tera-clone/services/tera-api/internal/snmpagent/snmpsocket" ) func main() { controller, err := snmpagent.NewOSController(snmpagent.OSOptions{ ConfigPath: getenv("TERA_SNMPD_CONFIG", snmpagent.DefaultConfigPath), PersistentPath: getenv("TERA_SNMPD_PERSISTENT_CONFIG", snmpagent.DefaultPersistentPath), InitScriptPath: getenv("TERA_SNMPD_INIT_SCRIPT", snmpagent.DefaultInitScriptPath), ServiceName: os.Getenv("TERA_SNMPD_SERVICE_NAME"), }) if err != nil { log.Fatalf("tera-snmpd setup failed: %v", err) } socketPath := getenv("TERA_SNMPD_SOCKET", snmpsocket.DefaultSocketPath) listener, err := listen(socketPath) if err != nil { log.Fatalf("tera-snmpd socket setup failed: %v", err) } defer func() { _ = listener.Close() _ = os.Remove(socketPath) }() done := make(chan error, 1) go func() { done <- (snmpsocket.Server{Controller: controller}).Serve(listener) }() log.Printf("tera-snmpd serving SNMP agent control on %s", socketPath) signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM) select { case signal := <-signals: log.Printf("tera-snmpd stopping after %s", signal) _ = listener.Close() if err := <-done; err != nil { log.Printf("tera-snmpd stop error: %v", err) } case err := <-done: if err != nil { log.Fatalf("tera-snmpd failed: %v", err) } } } func listen(socketPath string) (net.Listener, error) { if socketPath == "" || !filepath.IsAbs(socketPath) { return nil, errors.New("TERA_SNMPD_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 SNMP 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 }