go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/services/manager.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package services
     5  
     6  import (
     7  	"errors"
     8  	"regexp"
     9  
    10  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    11  	"go.mondoo.com/cnquery/providers/os/detector"
    12  )
    13  
    14  type Service struct {
    15  	Name        string
    16  	Description string
    17  	State       State
    18  	Type        string
    19  	Installed   bool
    20  	Running     bool
    21  	Enabled     bool
    22  	Masked      bool
    23  }
    24  
    25  type State string
    26  
    27  const (
    28  	ServiceContinuePending State = "ServiceContinuePending"
    29  	ServicePausePending    State = "ServicePausePending"
    30  	ServicePaused          State = "ServicePaused"
    31  	ServiceRunning         State = "ServiceRunning"
    32  	ServiceStartPending    State = "ServiceStartPending"
    33  	ServiceStopPending     State = "ServiceStopPending"
    34  	ServiceStopped         State = "ServiceStopped"
    35  	ServiceUnknown         State = "ServiceUnknown"
    36  )
    37  
    38  type OSServiceManager interface {
    39  	Name() string
    40  	List() ([]*Service, error)
    41  }
    42  
    43  var amazonlinux1version = regexp.MustCompile(`^201\d`)
    44  
    45  func ResolveManager(conn shared.Connection) (OSServiceManager, error) {
    46  	var osm OSServiceManager
    47  
    48  	asset := conn.Asset()
    49  	if asset == nil || asset.Platform == nil {
    50  		return nil, errors.New("cannot find OS information for package detection")
    51  	}
    52  
    53  	switch {
    54  	case asset.Platform.IsFamily("arch"): // arch family
    55  		osm = ResolveSystemdServiceManager(conn)
    56  	case asset.Platform.Name == "amazonlinux":
    57  		if amazonlinux1version.MatchString(asset.Platform.Version) {
    58  			osm = &UpstartServiceManager{SysVServiceManager{conn: conn}}
    59  		} else {
    60  			osm = ResolveSystemdServiceManager(conn)
    61  		}
    62  	case asset.Platform.Name == "photon":
    63  		osm = ResolveSystemdServiceManager(conn)
    64  	// NOTE: we need to check fedora before rhel family, since its also rhel family
    65  	case asset.Platform.Name == "fedora":
    66  		rv := detector.ParseOsVersion(asset.Platform.Version)
    67  		v, err := rv.MajorAtoi()
    68  		if err != nil {
    69  			return nil, errors.New("unknown fedora version: " + asset.Platform.Version)
    70  		}
    71  
    72  		if v < 15 {
    73  			// upstart is only used since fedora 11 but we do not support those older versions
    74  			osm = &UpstartServiceManager{SysVServiceManager{conn: conn}}
    75  		} else {
    76  			osm = ResolveSystemdServiceManager(conn)
    77  		}
    78  	case asset.Platform.IsFamily("redhat"):
    79  		rv := detector.ParseOsVersion(asset.Platform.Version)
    80  		v, err := rv.MajorAtoi()
    81  		if err != nil {
    82  			return nil, errors.New("unknown redhat version: " + asset.Platform.Version)
    83  		}
    84  		if v < 7 {
    85  			osm = &UpstartServiceManager{SysVServiceManager{conn: conn}}
    86  		} else {
    87  			osm = ResolveSystemdServiceManager(conn)
    88  		}
    89  	case asset.Platform.Name == "ubuntu" || asset.Platform.Name == "linuxmint" || asset.Platform.Name == "pop":
    90  		rv := detector.ParseOsVersion(asset.Platform.Version)
    91  		v, err := rv.MajorAtoi()
    92  		if err != nil {
    93  			return nil, errors.New("unknown ubuntu version: " + asset.Platform.Version)
    94  		}
    95  
    96  		if v < 15 {
    97  			osm = &UpstartServiceManager{SysVServiceManager{conn: conn}}
    98  		} else {
    99  			osm = ResolveSystemdServiceManager(conn)
   100  		}
   101  	case asset.Platform.Name == "debian":
   102  		rv := detector.ParseOsVersion(asset.Platform.Version)
   103  		v, err := rv.MajorAtoi()
   104  		if err != nil {
   105  			return nil, errors.New("unknown debian version: " + asset.Platform.Version)
   106  		}
   107  
   108  		if v < 7 {
   109  			osm = &SysVServiceManager{conn: conn}
   110  		} else {
   111  			osm = ResolveSystemdServiceManager(conn)
   112  		}
   113  	case asset.Platform.Name == "raspbian":
   114  		osm = ResolveSystemdServiceManager(conn)
   115  	case asset.Platform.Name == "suse-microos": // it is suse family but uses a different version scheme
   116  		osm = ResolveSystemdServiceManager(conn)
   117  	case asset.Platform.IsFamily("suse"):
   118  		rv := detector.ParseOsVersion(asset.Platform.Version)
   119  		v, err := rv.MajorAtoi()
   120  		if err != nil {
   121  			return nil, errors.New("unknown suse version: " + asset.Platform.Version)
   122  		}
   123  
   124  		// NOTE: opensuse-tumbleweed uses version numbers like 20200622
   125  		if v < 12 {
   126  			osm = &SysVServiceManager{conn: conn}
   127  		} else {
   128  			osm = ResolveSystemdServiceManager(conn)
   129  		}
   130  	case asset.Platform.IsFamily("darwin"): // "macos", "darwin"
   131  		osm = &LaunchDServiceManager{conn: conn}
   132  	case asset.Platform.Name == "freebsd" || asset.Platform.Name == "dragonflybsd" || asset.Platform.Name == "netbsd":
   133  		osm = &BsdInitServiceManager{conn: conn}
   134  	case asset.Platform.Name == "openbsd":
   135  		osm = &OpenBsdRcctlServiceManager{conn: conn}
   136  	case asset.Platform.Name == "windows":
   137  		osm = &WindowsServiceManager{conn: conn}
   138  	case asset.Platform.Name == "alpine":
   139  		osm = &AlpineOpenrcServiceManager{conn: conn}
   140  	case asset.Platform.Name == "cos":
   141  		osm = ResolveSystemdServiceManager(conn)
   142  	case asset.Platform.Name == "aix":
   143  		osm = &AixServiceManager{conn: conn}
   144  	case asset.Platform.Name == "kali": // debian based with versions from 2015 onwards being systemd based
   145  		osm = ResolveSystemdServiceManager(conn)
   146  	}
   147  
   148  	if osm == nil {
   149  		return nil, errors.New("could not detect suitable service manager for platform: " + asset.Platform.Name)
   150  	}
   151  
   152  	return osm, nil
   153  }
   154  
   155  func FindService(services []*Service, name string) (*Service, error) {
   156  	// search for name
   157  	for i := range services {
   158  		service := services[i]
   159  		if service.Name == name {
   160  			return service, nil
   161  		}
   162  	}
   163  
   164  	return nil, errors.New("service> " + name + " does not exist")
   165  }