Files
scrutiny/vendor/github.com/jaypipes/pcidb/main.go
T
2020-08-21 06:31:48 +00:00

182 lines
5.2 KiB
Go

//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//
package pcidb
import (
"fmt"
"os"
"strconv"
)
var (
ERR_NO_DB = fmt.Errorf("No pci-ids DB files found (and network fetch disabled)")
trueVar = true
)
// ProgrammingInterface is the PCI programming interface for a class of PCI
// devices
type ProgrammingInterface struct {
// hex-encoded PCI_ID of the programming interface
ID string `json:"id"`
// common string name for the programming interface
Name string `json:"name"`
}
// Subclass is a subdivision of a PCI class
type Subclass struct {
// hex-encoded PCI_ID for the device subclass
ID string `json:"id"`
// common string name for the subclass
Name string `json:"name"`
// any programming interfaces this subclass might have
ProgrammingInterfaces []*ProgrammingInterface `json:"programming_interfaces"`
}
// Class is the PCI class
type Class struct {
// hex-encoded PCI_ID for the device class
ID string `json:"id"`
// common string name for the class
Name string `json:"name"`
// any subclasses belonging to this class
Subclasses []*Subclass `json:"subclasses"`
}
// Product provides information about a PCI device model
// NOTE(jaypipes): In the hardware world, the PCI "device_id" is the identifier
// for the product/model
type Product struct {
// vendor ID for the product
VendorID string `json:"vendor_id"`
// hex-encoded PCI_ID for the product/model
ID string `json:"id"`
// common string name of the vendor
Name string `json:"name"`
// "subdevices" or "subsystems" for the product
Subsystems []*Product `json:"subsystems"`
}
// Vendor provides information about a device vendor
type Vendor struct {
// hex-encoded PCI_ID for the vendor
ID string `json:"id"`
// common string name of the vendor
Name string `json:"name"`
// all top-level devices for the vendor
Products []*Product `json:"products"`
}
type PCIDB struct {
// hash of class ID -> class information
Classes map[string]*Class `json:"classes"`
// hash of vendor ID -> vendor information
Vendors map[string]*Vendor `json:"vendors"`
// hash of vendor ID + product/device ID -> product information
Products map[string]*Product `json:"products"`
}
// WithOption is used to represent optionally-configured settings
type WithOption struct {
// Chroot is the directory that pcidb uses when attempting to discover
// pciids DB files
Chroot *string
// CacheOnly is mostly just useful for testing. It essentially disables
// looking for any non ~/.cache/pci.ids filepaths (which is useful when we
// want to test the fetch-from-network code paths
CacheOnly *bool
// Disables the default behaviour of fetching a pci-ids from a known
// location on the network if no local pci-ids DB files can be found.
// Useful for secure environments or environments with no network
// connectivity.
DisableNetworkFetch *bool
}
func WithChroot(dir string) *WithOption {
return &WithOption{Chroot: &dir}
}
func WithCacheOnly() *WithOption {
return &WithOption{CacheOnly: &trueVar}
}
func WithDisableNetworkFetch() *WithOption {
return &WithOption{DisableNetworkFetch: &trueVar}
}
func mergeOptions(opts ...*WithOption) *WithOption {
// Grab options from the environs by default
defaultChroot := "/"
if val, exists := os.LookupEnv("PCIDB_CHROOT"); exists {
defaultChroot = val
}
defaultCacheOnly := false
if val, exists := os.LookupEnv("PCIDB_CACHE_ONLY"); exists {
if parsed, err := strconv.ParseBool(val); err != nil {
fmt.Fprintf(
os.Stderr,
"Failed parsing a bool from PCIDB_CACHE_ONLY "+
"environ value of %s",
val,
)
} else if parsed {
defaultCacheOnly = parsed
}
}
defaultDisableNetworkFetch := false
if val, exists := os.LookupEnv("PCIDB_DISABLE_NETWORK_FETCH"); exists {
if parsed, err := strconv.ParseBool(val); err != nil {
fmt.Fprintf(
os.Stderr,
"Failed parsing a bool from PCIDB_DISABLE_NETWORK_FETCH "+
"environ value of %s",
val,
)
} else if parsed {
defaultDisableNetworkFetch = parsed
}
}
merged := &WithOption{}
for _, opt := range opts {
if opt.Chroot != nil {
merged.Chroot = opt.Chroot
}
if opt.CacheOnly != nil {
merged.CacheOnly = opt.CacheOnly
}
if opt.DisableNetworkFetch != nil {
merged.DisableNetworkFetch = opt.DisableNetworkFetch
}
}
// Set the default value if missing from merged
if merged.Chroot == nil {
merged.Chroot = &defaultChroot
}
if merged.CacheOnly == nil {
merged.CacheOnly = &defaultCacheOnly
}
if merged.DisableNetworkFetch == nil {
merged.DisableNetworkFetch = &defaultDisableNetworkFetch
}
return merged
}
// New returns a pointer to a PCIDB struct which contains information you can
// use to query PCI vendor, product and class information. It accepts zero or
// more pointers to WithOption structs. If you want to modify the behaviour of
// pcidb, use one of the option modifiers when calling New. For example, to
// change the root directory that pcidb uses when discovering pciids DB files,
// call New(WithChroot("/my/root/override"))
func New(opts ...*WithOption) (*PCIDB, error) {
ctx := contextFromOptions(mergeOptions(opts...))
db := &PCIDB{}
if err := db.load(ctx); err != nil {
return nil, err
}
return db, nil
}