diff --git a/agent/systemd.go b/agent/systemd.go index 97b75a0a..6dca6c76 100644 --- a/agent/systemd.go +++ b/agent/systemd.go @@ -8,6 +8,7 @@ import ( "log/slog" "maps" "math" + "os" "strconv" "strings" "sync" @@ -19,6 +20,24 @@ import ( var errNoActiveTime = errors.New("no active time") +// isSystemdAvailable checks if systemd is running as the init system (PID 1). +// This prevents unnecessary connection attempts on systems using other init systems +// like OpenRC, runit, or when running in containers without systemd. +func isSystemdAvailable() bool { + // Check if /run/systemd/system directory exists - this is a reliable indicator + // that systemd is running as the init system + if _, err := os.Stat("/run/systemd/system"); err == nil { + return true + } + + // Fallback: check if PID 1 is systemd by reading /proc/1/comm + if data, err := os.ReadFile("/proc/1/comm"); err == nil { + return strings.TrimSpace(string(data)) == "systemd" + } + + return false +} + // systemdManager manages the collection of systemd service statistics. type systemdManager struct { sync.Mutex @@ -33,6 +52,13 @@ func newSystemdManager() (*systemdManager, error) { if skipSystemd, _ := GetEnv("SKIP_SYSTEMD"); skipSystemd == "true" { return nil, nil } + + // Check if systemd is available on the system before attempting connection + if !isSystemdAvailable() { + slog.Debug("Systemd not available on this system") + return nil, nil + } + conn, err := dbus.NewSystemConnectionContext(context.Background()) if err != nil { slog.Debug("Error connecting to systemd", "err", err, "ref", "https://beszel.dev/guide/systemd") diff --git a/agent/systemd_test.go b/agent/systemd_test.go index a1bd59aa..8d726370 100644 --- a/agent/systemd_test.go +++ b/agent/systemd_test.go @@ -4,6 +4,7 @@ package agent import ( "os" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -48,6 +49,35 @@ func TestUnescapeServiceNameInvalid(t *testing.T) { } } +func TestIsSystemdAvailable(t *testing.T) { + // Note: This test's result will vary based on the actual system running the tests + // On systems with systemd, it should return true + // On systems without systemd, it should return false + result := isSystemdAvailable() + + // Check if either the /run/systemd/system directory exists or PID 1 is systemd + runSystemdExists := false + if _, err := os.Stat("/run/systemd/system"); err == nil { + runSystemdExists = true + } + + pid1IsSystemd := false + if data, err := os.ReadFile("/proc/1/comm"); err == nil { + pid1IsSystemd = strings.TrimSpace(string(data)) == "systemd" + } + + expected := runSystemdExists || pid1IsSystemd + + assert.Equal(t, expected, result, "isSystemdAvailable should correctly detect systemd presence") + + // Log the result for informational purposes + if result { + t.Log("Systemd is available on this system") + } else { + t.Log("Systemd is not available on this system") + } +} + func TestGetServicePatterns(t *testing.T) { tests := []struct { name string