64 lines
1.4 KiB
Go
64 lines
1.4 KiB
Go
package packages
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"io"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// OSRelease identifies the distribution well enough to select an advisory
|
|
// feed. VersionID is not optional: Ubuntu 22.04 and 24.04 publish different
|
|
// fixed versions for the same CVE.
|
|
type OSRelease struct {
|
|
Family string
|
|
VersionID string
|
|
Arch string
|
|
}
|
|
|
|
// ParseOSRelease reads the os-release format: KEY=value, one per line, with
|
|
// values optionally quoted, and # comments.
|
|
//
|
|
// The quote stripping handles both ID=ubuntu and ID="rocky", which real
|
|
// distributions both emit.
|
|
func ParseOSRelease(r io.Reader) (OSRelease, error) {
|
|
out := OSRelease{Arch: runtime.GOARCH}
|
|
sc := bufio.NewScanner(r)
|
|
for sc.Scan() {
|
|
line := strings.TrimSpace(sc.Text())
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
continue
|
|
}
|
|
key, val, ok := strings.Cut(line, "=")
|
|
if !ok {
|
|
continue
|
|
}
|
|
val = strings.Trim(strings.TrimSpace(val), `"'`)
|
|
switch strings.TrimSpace(key) {
|
|
case "ID":
|
|
out.Family = strings.ToLower(val)
|
|
case "VERSION_ID":
|
|
out.VersionID = val
|
|
}
|
|
}
|
|
if err := sc.Err(); err != nil {
|
|
return OSRelease{}, err
|
|
}
|
|
if out.Family == "" {
|
|
return OSRelease{}, errors.New("os-release has no ID")
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// DetectOS reads /etc/os-release.
|
|
func DetectOS() (OSRelease, error) {
|
|
f, err := os.Open("/etc/os-release")
|
|
if err != nil {
|
|
return OSRelease{}, err
|
|
}
|
|
defer f.Close()
|
|
return ParseOSRelease(f)
|
|
}
|