182 lines
5.2 KiB
Go
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
|
|
}
|