go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/detector/os_release.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package detector
     5  
     6  import (
     7  	"io"
     8  	"regexp"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/rs/zerolog/log"
    13  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    14  )
    15  
    16  func NewOSReleaseDetector(conn shared.Connection) *OSReleaseDetector {
    17  	return &OSReleaseDetector{
    18  		provider: conn,
    19  	}
    20  }
    21  
    22  type OSReleaseDetector struct {
    23  	provider shared.Connection
    24  }
    25  
    26  func (d *OSReleaseDetector) command(command string) (string, error) {
    27  	cmd, err := d.provider.RunCommand(command)
    28  	if err != nil {
    29  		log.Debug().Err(err).Msg("could not execute os release detection command")
    30  		return "", err
    31  	}
    32  
    33  	content, err := io.ReadAll(cmd.Stdout)
    34  	if err != nil {
    35  		return "", err
    36  	}
    37  
    38  	return strings.TrimSpace(string(content)), nil
    39  }
    40  
    41  // UNIX helper methods
    42  // operating system name
    43  func (d *OSReleaseDetector) unames() (string, error) {
    44  	return d.command("uname -s")
    45  }
    46  
    47  // operating system release
    48  func (d *OSReleaseDetector) unamer() (string, error) {
    49  	return d.command("uname -r")
    50  }
    51  
    52  // machine hardware name
    53  func (d *OSReleaseDetector) unamem() (string, error) {
    54  	return d.command("uname -m")
    55  }
    56  
    57  // osrelease reads /etc/os/release and parses the file
    58  // NAME="Ubuntu"
    59  // VERSION="16.04.3 LTS (Xenial Xerus)"
    60  // ID=ubuntu
    61  // ID_LIKE=debian
    62  // PRETTY_NAME="Ubuntu 16.04.3 LTS"
    63  // VERSION_ID="16.04"
    64  // HOME_URL="http://www.ubuntu.com/"
    65  // SUPPORT_URL="http://help.ubuntu.com/"
    66  // BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
    67  // VERSION_CODENAME=xenial
    68  // UBUNTU_CODENAME=xenial
    69  func (d *OSReleaseDetector) osrelease() (map[string]string, error) {
    70  	f, err := d.provider.FileSystem().Open("/etc/os-release")
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	defer f.Close()
    75  
    76  	content, err := io.ReadAll(f)
    77  	if err != nil {
    78  		return nil, err
    79  	}
    80  
    81  	return ParseOsRelease(string(content))
    82  }
    83  
    84  // lsbconfig reads /etc/lsb-release and parses the file
    85  // DISTRIB_ID=Ubuntu
    86  // DISTRIB_RELEASE=16.04
    87  // DISTRIB_CODENAME=xenial
    88  // DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"
    89  // lsb release is not the default on newer systems, but can still be used
    90  // as a fallback mechanism
    91  func (d *OSReleaseDetector) lsbconfig() (map[string]string, error) {
    92  	f, err := d.provider.FileSystem().Open("/etc/lsb-release")
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  	defer f.Close()
    97  
    98  	content, err := io.ReadAll(f)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return ParseLsbRelease(string(content))
   104  }
   105  
   106  // darwin_swversion will call `/usr/bin/sw_vers` to identify the
   107  // version of darwin. A common output would be:
   108  // ```                                                                                                                  3d master[97c5c29]
   109  // ProductName:	Mac OS X
   110  // ProductVersion:	10.13.2
   111  // BuildVersion:	17C88
   112  // ````
   113  func (d *OSReleaseDetector) darwin_swversion() (map[string]string, error) {
   114  	content, err := d.command("/usr/bin/sw_vers")
   115  	if err != nil {
   116  		return nil, err
   117  	}
   118  	return ParseDarwinRelease(content)
   119  }
   120  
   121  // macosSystemVersion is a specifc identifier for the operating system on macos
   122  func (d *OSReleaseDetector) macosSystemVersion() (map[string]string, error) {
   123  	f, err := d.provider.FileSystem().Open("/System/Library/CoreServices/SystemVersion.plist")
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	defer f.Close()
   128  
   129  	content, err := io.ReadAll(f)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	return ParseMacOSSystemVersion(string(content))
   135  }
   136  
   137  var majorminor = regexp.MustCompile(`^(\d+)(?:.(\d*)){0,1}(?:.(.*)){0,1}`)
   138  
   139  type ReleaseVersion struct {
   140  	Major string
   141  	Minor string
   142  	Other string
   143  }
   144  
   145  func (v ReleaseVersion) MajorAtoi() (int, error) {
   146  	return strconv.Atoi(v.Major)
   147  }
   148  
   149  func ParseOsVersion(v string) ReleaseVersion {
   150  	m := majorminor.FindStringSubmatch(v)
   151  	if len(m) == 0 {
   152  		return ReleaseVersion{Major: v}
   153  	}
   154  
   155  	return ReleaseVersion{Major: m[1], Minor: m[2], Other: m[3]}
   156  }