syft/imgbom/distro/identify.go
Alfredo Deza e2b71184aa when no distros are matched, return an UnkownDistro
Signed-off-by: Alfredo Deza <adeza@anchore.com>
2020-07-17 13:32:53 -04:00

119 lines
2.6 KiB
Go

package distro
import (
"regexp"
"strings"
"github.com/anchore/imgbom/imgbom/scope"
"github.com/anchore/imgbom/internal/log"
"github.com/anchore/stereoscope/pkg/file"
)
// returns a distro or nil
type parseFunc func(string) *Distro
// Identify parses distro-specific files to determine distro metadata like version and release
func Identify(s scope.Scope) *Distro {
identityFiles := map[file.Path]parseFunc{
"/etc/os-release": parseOsRelease,
// Debian and Debian-based distros have the same contents linked from this path
"/usr/lib/os-release": parseOsRelease,
"/bin/busybox": parseBusyBox,
}
for path, fn := range identityFiles {
refs, err := s.FilesByPath(path)
if err != nil {
log.Errorf("unable to get path refs from %s: %s", path, err)
return nil
}
if len(refs) == 0 {
continue
}
for _, ref := range refs {
contents, err := s.MultipleFileContentsByRef(ref)
content, ok := contents[ref]
if !ok {
log.Infof("no content present for ref: %s", ref)
continue
}
if err != nil {
log.Debugf("unable to get contents from %s: %s", path, err)
continue
}
if content == "" {
log.Debugf("no contents in file, skipping: %s", path)
continue
}
distro := fn(content)
if distro == nil {
continue
}
return distro
}
}
// TODO: is it useful to know partially detected distros? where the ID is known but not the version (and viceversa?)
distro := NewUnknownDistro()
return &distro
}
func assembleDistro(name, version string) *Distro {
distroType, ok := Mappings[name]
// Both distro and version must be present
if len(name) == 0 || len(version) == 0 {
return nil
}
if ok {
distro, err := NewDistro(distroType, version)
if err != nil {
return nil
}
return &distro
}
return nil
}
func parseOsRelease(contents string) *Distro {
id, vers := "", ""
for _, line := range strings.Split(contents, "\n") {
parts := strings.Split(line, "=")
prefix := parts[0]
value := strings.ReplaceAll(parts[len(parts)-1], `"`, "")
switch prefix {
case "ID":
id = strings.TrimSpace(value)
case "VERSION_ID":
vers = strings.TrimSpace(value)
}
}
return assembleDistro(id, vers)
}
var busyboxVersionMatcher = regexp.MustCompile(`BusyBox v[\d\.]+`)
func parseBusyBox(contents string) *Distro {
matches := busyboxVersionMatcher.FindAllString(contents, -1)
for _, match := range matches {
parts := strings.Split(match, " ")
version := strings.ReplaceAll(parts[1], "v", "")
distro := assembleDistro("busybox", version)
if distro != nil {
return distro
}
}
return nil
}