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

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package yum
     5  
     6  // To support static analysis, we need to extend the current implementation:
     7  //
     8  // - read repo info from file system as is
     9  // - read variables from file system as is
    10  
    11  // https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-using_yum_variables
    12  // /etc/yum.conf
    13  // /etc/yum.repos.d/*.repo
    14  
    15  // References:
    16  // - https://unix.stackexchange.com/questions/19701/yum-how-can-i-view-variables-like-releasever-basearch-yum0
    17  // - https://docs.centos.org/en-US/8-docs/managing-userspace-components/assembly_using-appstream/
    18  
    19  import (
    20  	"bufio"
    21  	"encoding/json"
    22  	"io"
    23  	"regexp"
    24  	"strings"
    25  )
    26  
    27  const (
    28  	RhelYumRepoListCommand = "yum -v repolist all"
    29  	DnfVarsCommand         = "%s -c 'import dnf, json; db = dnf.dnf.Base(); print(json.dumps(db.conf.substitutions))'"
    30  	PythonRhel             = "/usr/libexec/platform-python"
    31  	Python3                = "python3"
    32  	Rhel6VarsCommand       = "python -c 'import yum, json; yb = yum.YumBase(); print json.dumps(yb.conf.yumvar)'"
    33  )
    34  
    35  type YumRepo struct {
    36  	Id       string
    37  	Name     string
    38  	Status   string
    39  	Revision string
    40  	Updated  string
    41  	Pkgs     string
    42  	Size     string
    43  	Mirrors  string
    44  	Expire   string
    45  	Filename string
    46  	Baseurl  []string
    47  	Filter   string
    48  }
    49  
    50  var (
    51  	yumrepoline = regexp.MustCompile(`^\s*([^:\s]*)(?:\s)*:\s(.*)$`)
    52  	yumbaseurl  = regexp.MustCompile(`^(.*?)(?:\(.*\))*$`)
    53  )
    54  
    55  const (
    56  	Id       = "Repo-id"
    57  	Name     = "Repo-name"
    58  	Status   = "Repo-status"
    59  	Revision = "Repo-revision"
    60  	Updated  = "Repo-updated"
    61  	Pkgs     = "Repo-pkgs"
    62  	Size     = "Repo-size"
    63  	Mirrors  = "Repo-mirrors"
    64  	Baseurl  = "Repo-baseurl"
    65  	Expire   = "Repo-expire"
    66  	Filter   = "Filter"
    67  	Filename = "Repo-filename"
    68  )
    69  
    70  func ParseVariables(r io.Reader) (map[string]string, error) {
    71  	content, err := io.ReadAll(r)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	data := map[string]string{}
    77  	err = json.Unmarshal(content, &data)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	return data, nil
    82  }
    83  
    84  // Parses the output of yum -v repolist all
    85  // It requires yum to be installed
    86  func ParseRepos(r io.Reader) ([]*YumRepo, error) {
    87  	res := []*YumRepo{}
    88  
    89  	var entry *YumRepo
    90  	add := func(new *YumRepo) {
    91  		if entry == nil {
    92  			return
    93  		}
    94  		res = append(res, new)
    95  	}
    96  	scanner := bufio.NewScanner(r)
    97  	for scanner.Scan() {
    98  		line := scanner.Text()
    99  		m := yumrepoline.FindStringSubmatch(line)
   100  		if len(m) == 3 {
   101  			key := strings.TrimSpace(m[1])
   102  			value := strings.TrimSpace(m[2])
   103  
   104  			switch key {
   105  			case Id:
   106  				add(entry)
   107  				entry = &YumRepo{Id: value}
   108  			case Name:
   109  				entry.Name = value
   110  			case Status:
   111  				entry.Status = value
   112  			case Revision:
   113  				entry.Revision = value
   114  			case Updated:
   115  				entry.Updated = value
   116  			case Pkgs:
   117  				entry.Pkgs = value
   118  			case Size:
   119  				entry.Size = value
   120  			case Mirrors:
   121  				entry.Mirrors = value
   122  			case Baseurl:
   123  				// remove (0 more)
   124  				// split by ,
   125  				m := yumbaseurl.FindStringSubmatch(value)
   126  				if m != nil && len(m) >= 2 {
   127  					entries := strings.Split(m[1], ",")
   128  					entry.Baseurl = []string{}
   129  					for i := range entries {
   130  						entry.Baseurl = append(entry.Baseurl, strings.TrimSpace(entries[i]))
   131  					}
   132  				}
   133  			case Expire:
   134  				entry.Expire = value
   135  			case Filter:
   136  				entry.Filter = value
   137  			case Filename:
   138  				entry.Filename = value
   139  			}
   140  		}
   141  	}
   142  
   143  	// add last entry
   144  	add(entry)
   145  
   146  	return res, nil
   147  }