diff --git a/providers/os/resources/services/aixlssrc.go b/providers/os/resources/services/aixlssrc.go new file mode 100644 index 0000000000..75ebd89b6a --- /dev/null +++ b/providers/os/resources/services/aixlssrc.go @@ -0,0 +1,66 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package services + +import ( + "bufio" + "go.mondoo.com/cnquery/providers/os/connection/shared" + "io" + "regexp" +) + +type AixServiceManager struct { + conn shared.Connection +} + +func (s *AixServiceManager) Name() string { + return "System Resource Controller" +} + +func (s *AixServiceManager) List() ([]*Service, error) { + cmd, err := s.conn.RunCommand("lssrc -a") + if err != nil { + return nil, err + } + + entries := parseLssrc(cmd.Stdout) + services := make([]*Service, len(entries)) + for i, entry := range entries { + services[i] = &Service{ + Name: entry.Subsystem, + Enabled: entry.Status == "active", + Installed: true, + Running: entry.Status == "active", + Type: "aix", + } + } + return services, nil +} + +type lssrcEntry struct { + Subsystem string + Group string + PID string + Status string +} + +var lssrcRegex = regexp.MustCompile(`^\s([\w.-]+)(\s+[\w]+\s+){0,1}([\d]+){0,1}\s+([\w]+)$`) + +func parseLssrc(input io.Reader) []lssrcEntry { + entries := []lssrcEntry{} + scanner := bufio.NewScanner(input) + for scanner.Scan() { + line := scanner.Text() + m := lssrcRegex.FindStringSubmatch(line) + if len(m) == 5 { + entries = append(entries, lssrcEntry{ + Subsystem: m[1], + Group: m[2], + PID: m[3], + Status: m[4], + }) + } + } + return entries +} diff --git a/providers/os/resources/services/aixlssrc_test.go b/providers/os/resources/services/aixlssrc_test.go new file mode 100644 index 0000000000..af43a0106c --- /dev/null +++ b/providers/os/resources/services/aixlssrc_test.go @@ -0,0 +1,35 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package services + +import ( + "github.com/stretchr/testify/assert" + "strings" + "testing" +) + +func TestLssrcParse(t *testing.T) { + testOutput := ` +Subsystem Group PID Status + syslogd ras 3932558 active + aso 4653462 active + biod nfs 5046692 active + rpc.lockd nfs 5636560 active + qdaemon spooler 5767630 active + ctrmc rsct 5439966 active + pmperfrec 6881768 active + IBM.HostRM rsct_rm 5898530 active + automountd autofs 7340402 active + lpd spooler inoperative + nimsh nimclient inoperative + nimhttp inoperative + timed tcpip inoperative +` + entries := parseLssrc(strings.NewReader(testOutput)) + assert.Equal(t, 13, len(entries), "detected the right amount of services") + assert.Equal(t, "syslogd", entries[0].Subsystem, "service name detected") + assert.Equal(t, "active", entries[0].Status, "service status detected") + assert.Equal(t, "timed", entries[12].Subsystem, "service name detected") + assert.Equal(t, "inoperative", entries[12].Status, "service status detected") +} diff --git a/providers/os/resources/services/manager.go b/providers/os/resources/services/manager.go index 6b7f24974d..00d4d80ab6 100644 --- a/providers/os/resources/services/manager.go +++ b/providers/os/resources/services/manager.go @@ -139,6 +139,8 @@ func ResolveManager(conn shared.Connection) (OSServiceManager, error) { osm = &AlpineOpenrcServiceManager{conn: conn} case asset.Platform.Name == "cos": osm = ResolveSystemdServiceManager(conn) + case asset.Platform.Name == "aix": + osm = &AixServiceManager{conn: conn} case asset.Platform.Name == "kali": // debian based with versions from 2015 onwards being systemd based osm = ResolveSystemdServiceManager(conn) }