From f517d79a42d580c46a54aadfd91e405b1cb8be56 Mon Sep 17 00:00:00 2001 From: Matthieu Bernardin Date: Tue, 24 Mar 2026 11:52:41 +0100 Subject: [PATCH] MGMT-23517: Bump go modules Unfortunately gwh is not exporting the Modifier struct, so 'any' is the way... --- go.mod | 10 +- go.sum | 20 +- src/inventory/disks_test.go | 2 +- src/inventory/system_vendor_test.go | 47 +- src/scanners/machine_uuid_scanner.go | 8 +- src/scanners/mock_SerialDiscovery.go | 30 +- src/util/dependencies.go | 24 +- src/util/mock_IDependencies.go | 86 +-- vendor/github.com/StackExchange/wmi/LICENSE | 20 - vendor/github.com/StackExchange/wmi/README.md | 13 - .../StackExchange/wmi/swbemservices.go | 260 -------- vendor/github.com/StackExchange/wmi/wmi.go | 590 ------------------ vendor/github.com/jaypipes/ghw/.gitignore | 1 + vendor/github.com/jaypipes/ghw/Makefile | 27 +- vendor/github.com/jaypipes/ghw/README.md | 303 +++++++-- vendor/github.com/jaypipes/ghw/SNAPSHOT.md | 10 +- vendor/github.com/jaypipes/ghw/alias.go | 34 +- vendor/github.com/jaypipes/ghw/host.go | 49 +- .../jaypipes/ghw/internal/config/context.go | 235 +++++++ .../jaypipes/ghw/internal/config/log.go | 156 +++++ .../jaypipes/ghw/internal/log/log.go | 57 ++ .../ghw/pkg/accelerator/accelerator.go | 19 +- .../ghw/pkg/accelerator/accelerator_linux.go | 10 +- .../ghw/pkg/accelerator/accelerator_stub.go | 7 +- .../pkg/accelerator/accelerator_windows.go | 13 + .../jaypipes/ghw/pkg/baseboard/baseboard.go | 16 +- .../ghw/pkg/baseboard/baseboard_linux.go | 14 +- .../ghw/pkg/baseboard/baseboard_stub.go | 3 +- .../ghw/pkg/baseboard/baseboard_windows.go | 6 +- .../github.com/jaypipes/ghw/pkg/bios/bios.go | 16 +- .../jaypipes/ghw/pkg/bios/bios_linux.go | 14 +- .../jaypipes/ghw/pkg/bios/bios_stub.go | 3 +- .../jaypipes/ghw/pkg/bios/bios_windows.go | 6 +- .../jaypipes/ghw/pkg/block/block.go | 23 +- .../jaypipes/ghw/pkg/block/block_darwin.go | 15 +- .../jaypipes/ghw/pkg/block/block_linux.go | 30 +- .../jaypipes/ghw/pkg/block/block_stub.go | 3 +- .../jaypipes/ghw/pkg/block/block_windows.go | 32 +- .../jaypipes/ghw/pkg/chassis/chassis.go | 16 +- .../jaypipes/ghw/pkg/chassis/chassis_linux.go | 14 +- .../jaypipes/ghw/pkg/chassis/chassis_stub.go | 3 +- .../ghw/pkg/chassis/chassis_windows.go | 6 +- .../jaypipes/ghw/pkg/context/context.go | 178 ------ vendor/github.com/jaypipes/ghw/pkg/cpu/cpu.go | 16 +- .../jaypipes/ghw/pkg/cpu/cpu_darwin.go | 6 +- .../jaypipes/ghw/pkg/cpu/cpu_linux.go | 77 ++- .../jaypipes/ghw/pkg/cpu/cpu_stub.go | 3 +- .../jaypipes/ghw/pkg/cpu/cpu_windows.go | 6 +- vendor/github.com/jaypipes/ghw/pkg/gpu/gpu.go | 16 +- .../jaypipes/ghw/pkg/gpu/gpu_linux.go | 50 +- .../jaypipes/ghw/pkg/gpu/gpu_stub.go | 3 +- .../jaypipes/ghw/pkg/gpu/gpu_windows.go | 9 +- .../jaypipes/ghw/pkg/linuxdmi/dmi_linux.go | 8 +- .../jaypipes/ghw/pkg/linuxpath/path_linux.go | 51 +- .../jaypipes/ghw/pkg/marshal/marshal.go | 9 +- .../jaypipes/ghw/pkg/memory/memory.go | 16 +- .../ghw/pkg/memory/memory_cache_linux.go | 89 ++- .../jaypipes/ghw/pkg/memory/memory_linux.go | 23 +- .../jaypipes/ghw/pkg/memory/memory_stub.go | 3 +- .../jaypipes/ghw/pkg/memory/memory_windows.go | 6 +- vendor/github.com/jaypipes/ghw/pkg/net/net.go | 16 +- .../jaypipes/ghw/pkg/net/net_linux.go | 25 +- .../jaypipes/ghw/pkg/net/net_stub.go | 3 +- .../jaypipes/ghw/pkg/net/net_windows.go | 5 +- .../jaypipes/ghw/pkg/option/option.go | 233 +++---- vendor/github.com/jaypipes/ghw/pkg/pci/pci.go | 92 +-- .../jaypipes/ghw/pkg/pci/pci_linux.go | 144 +++-- .../jaypipes/ghw/pkg/pci/pci_stub.go | 3 +- .../jaypipes/ghw/pkg/product/product.go | 16 +- .../jaypipes/ghw/pkg/product/product_linux.go | 19 +- .../jaypipes/ghw/pkg/product/product_stub.go | 3 +- .../ghw/pkg/product/product_windows.go | 6 +- .../jaypipes/ghw/pkg/snapshot/clonetree.go | 198 ------ .../ghw/pkg/snapshot/clonetree_block_linux.go | 220 ------- .../ghw/pkg/snapshot/clonetree_gpu_linux.go | 33 - .../ghw/pkg/snapshot/clonetree_linux.go | 109 ---- .../ghw/pkg/snapshot/clonetree_net_linux.go | 28 - .../ghw/pkg/snapshot/clonetree_pci_linux.go | 150 ----- .../ghw/pkg/snapshot/clonetree_stub.go | 30 - .../jaypipes/ghw/pkg/snapshot/pack.go | 111 ---- .../jaypipes/ghw/pkg/snapshot/testdata.tar.gz | Bin 485 -> 0 bytes .../jaypipes/ghw/pkg/snapshot/trace.go | 17 - .../jaypipes/ghw/pkg/snapshot/unpack.go | 128 ---- .../jaypipes/ghw/pkg/topology/topology.go | 23 +- .../ghw/pkg/topology/topology_linux.go | 28 +- .../ghw/pkg/topology/topology_stub.go | 3 +- .../ghw/pkg/topology/topology_windows.go | 3 +- vendor/github.com/jaypipes/ghw/pkg/usb/usb.go | 112 ++++ .../jaypipes/ghw/pkg/usb/usb_linux.go | 116 ++++ .../jaypipes/ghw/pkg/usb/usb_stub.go | 20 + .../github.com/jaypipes/ghw/pkg/util/util.go | 9 +- vendor/github.com/jaypipes/pcidb/README.md | 250 +++++--- vendor/github.com/jaypipes/pcidb/context.go | 86 --- vendor/github.com/jaypipes/pcidb/discover.go | 111 ---- .../jaypipes/pcidb/internal/discover.go | 168 +++++ .../jaypipes/pcidb/internal/option.go | 82 +++ .../jaypipes/pcidb/{ => internal}/parse.go | 72 ++- vendor/github.com/jaypipes/pcidb/main.go | 196 ------ vendor/github.com/jaypipes/pcidb/pcidb.go | 66 ++ .../github.com/jaypipes/pcidb/types/class.go | 17 + vendor/github.com/jaypipes/pcidb/types/db.go | 17 + .../jaypipes/pcidb/types/default.go | 35 ++ vendor/github.com/jaypipes/pcidb/types/env.go | 15 + .../github.com/jaypipes/pcidb/types/error.go | 20 + .../github.com/jaypipes/pcidb/types/option.go | 66 ++ .../jaypipes/pcidb/types/product.go | 22 + .../pcidb/types/programming_interface.go | 16 + .../jaypipes/pcidb/types/subclass.go | 18 + .../github.com/jaypipes/pcidb/types/vendor.go | 17 + .../github.com/mitchellh/go-homedir/LICENSE | 21 - .../github.com/mitchellh/go-homedir/README.md | 14 - .../mitchellh/go-homedir/homedir.go | 167 ----- vendor/github.com/yusufpapurcu/wmi/wmi.go | 12 + vendor/howett.net/plist/bplist_parser.go | 5 +- vendor/howett.net/plist/marshal.go | 48 +- vendor/howett.net/plist/text_parser.go | 6 + vendor/howett.net/plist/typeinfo.go | 79 ++- vendor/howett.net/plist/unmarshal.go | 40 +- vendor/modules.txt | 21 +- 119 files changed, 2677 insertions(+), 3733 deletions(-) delete mode 100644 vendor/github.com/StackExchange/wmi/LICENSE delete mode 100644 vendor/github.com/StackExchange/wmi/README.md delete mode 100644 vendor/github.com/StackExchange/wmi/swbemservices.go delete mode 100644 vendor/github.com/StackExchange/wmi/wmi.go create mode 100644 vendor/github.com/jaypipes/ghw/internal/config/context.go create mode 100644 vendor/github.com/jaypipes/ghw/internal/config/log.go create mode 100644 vendor/github.com/jaypipes/ghw/internal/log/log.go create mode 100644 vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_windows.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/context/context.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_block_linux.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_gpu_linux.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_linux.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_net_linux.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_pci_linux.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_stub.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/pack.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/testdata.tar.gz delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/trace.go delete mode 100644 vendor/github.com/jaypipes/ghw/pkg/snapshot/unpack.go create mode 100644 vendor/github.com/jaypipes/ghw/pkg/usb/usb.go create mode 100644 vendor/github.com/jaypipes/ghw/pkg/usb/usb_linux.go create mode 100644 vendor/github.com/jaypipes/ghw/pkg/usb/usb_stub.go delete mode 100644 vendor/github.com/jaypipes/pcidb/context.go delete mode 100644 vendor/github.com/jaypipes/pcidb/discover.go create mode 100644 vendor/github.com/jaypipes/pcidb/internal/discover.go create mode 100644 vendor/github.com/jaypipes/pcidb/internal/option.go rename vendor/github.com/jaypipes/pcidb/{ => internal}/parse.go (72%) delete mode 100644 vendor/github.com/jaypipes/pcidb/main.go create mode 100644 vendor/github.com/jaypipes/pcidb/pcidb.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/class.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/db.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/default.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/env.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/error.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/option.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/product.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/programming_interface.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/subclass.go create mode 100644 vendor/github.com/jaypipes/pcidb/types/vendor.go delete mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE delete mode 100644 vendor/github.com/mitchellh/go-homedir/README.md delete mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go diff --git a/go.mod b/go.mod index 40f71838a..a3fbf6b21 100644 --- a/go.mod +++ b/go.mod @@ -14,8 +14,8 @@ require ( github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.7.0 - github.com/jaypipes/ghw v0.16.0 - github.com/jaypipes/pcidb v1.0.1 + github.com/jaypipes/ghw v0.23.0 + github.com/jaypipes/pcidb v1.1.1 github.com/jinzhu/copier v0.4.0 github.com/kelseyhightower/envconfig v1.4.0 github.com/onsi/ginkgo v1.16.5 @@ -74,7 +74,7 @@ require ( github.com/tklauser/go-sysconf v0.3.12 // indirect github.com/tklauser/numcpus v0.6.1 // indirect github.com/x448/float16 v0.8.4 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect go.opentelemetry.io/otel v1.24.0 // indirect go.opentelemetry.io/otel/metric v1.24.0 // indirect @@ -91,7 +91,6 @@ require ( require ( github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/StackExchange/wmi v1.2.1 // indirect github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect @@ -140,7 +139,6 @@ require ( github.com/json-iterator/go v1.1.12 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/microcosm-cc/bluemonday v1.0.26 // indirect - github.com/mitchellh/go-homedir v1.1.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -175,7 +173,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect gorm.io/driver/postgres v1.3.5 // indirect gorm.io/gorm v1.25.8 // indirect - howett.net/plist v1.0.0 // indirect + howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 // indirect k8s.io/api v0.34.3 // indirect k8s.io/apimachinery v0.34.3 // indirect k8s.io/client-go v0.34.3 // indirect diff --git a/go.sum b/go.sum index 0cc09af04..1af3685f7 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/rehttp v1.4.0 h1:rIN7A2s+O9fmHUM1vUcInvlHj9Ysql4hE+Y0wcl/xk8= github.com/PuerkitoBio/rehttp v1.4.0/go.mod h1:LUwKPoDbDIA2RL5wYZCNsQ90cx4OJ4AWBmq6KzWZL1s= github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= -github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 h1:s6gZFSlWYmbqAuRjVTiNNhvNRfY2Wxp9nhfyel4rklc= github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137/go.mod h1:OMCwj8VM1Kc9e19TLln2VL61YJF0x1XFtfdL4JdbSyE= github.com/alessio/shellescape v1.4.2 h1:MHPfaU+ddJ0/bYWpgIeUnQUqKrlJ1S7BfEYPM4uEoM0= @@ -185,7 +183,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= @@ -365,10 +362,10 @@ github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76 github.com/jackc/pgx/v4 v4.18.3 h1:dE2/TrEsGX3RBprb3qryqSV9Y60iZN1C6i8IrmW9/BA= github.com/jackc/pgx/v4 v4.18.3/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jaypipes/ghw v0.16.0 h1:3HurCTS38VNpeQLo5fIdZsySuo/qAfpPSJ5t05QBFPM= -github.com/jaypipes/ghw v0.16.0/go.mod h1:In8SsaDqlb1oTyrbmTC14uy+fbBMvp+xdqX51MidlD8= -github.com/jaypipes/pcidb v1.0.1 h1:WB2zh27T3nwg8AE8ei81sNRb9yWBii3JGNJtT7K9Oic= -github.com/jaypipes/pcidb v1.0.1/go.mod h1:6xYUz/yYEyOkIkUt2t2J2folIuZ4Yg6uByCGFXMCeE4= +github.com/jaypipes/ghw v0.23.0 h1:WOL4hpLcIu1kIm+z5Oz19Tk1HNw/Sncrx/6GS8O0Kl0= +github.com/jaypipes/ghw v0.23.0/go.mod h1:fUNUjMZ0cjahKo+/u+32m9FutIx53Nkbi0Ti0m7j5HY= +github.com/jaypipes/pcidb v1.1.1 h1:QmPhpsbmmnCwZmHeYAATxEaoRuiMAJusKYkUncMC0ro= +github.com/jaypipes/pcidb v1.1.1/go.mod h1:x27LT2krrUgjf875KxQXKB0Ha/YXLdZRVmw6hH0G7g8= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= @@ -421,7 +418,6 @@ github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvls github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= -github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= @@ -600,8 +596,9 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= @@ -1051,7 +1048,6 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -1078,8 +1074,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= -howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= +howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 h1:eeH1AIcPvSc0Z25ThsYF+Xoqbn0CI/YnXVYoTLFdGQw= +howett.net/plist v1.0.2-0.20250314012144-ee69052608d9/go.mod h1:fyFX5Hj5tP1Mpk8obqA9MZgXT416Q5711SDT7dQLTLk= k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg= k8s.io/api v0.34.3 h1:D12sTP257/jSH2vHV2EDYrb16bS7ULlHpdNdNhEw2S4= k8s.io/api v0.34.3/go.mod h1:PyVQBF886Q5RSQZOim7DybQjAbVs8g7gwJNhGtY5MBk= diff --git a/src/inventory/disks_test.go b/src/inventory/disks_test.go index 694e3290d..a977b1cd7 100644 --- a/src/inventory/disks_test.go +++ b/src/inventory/disks_test.go @@ -359,7 +359,7 @@ func incrementFileInfoNameCall(dependencies *util.MockIDependencies, id string) } func mockFetchDisks(dependencies *util.MockIDependencies, error error, disks ...*ghw.Disk) { - dependencies.On("Block", ghw.WithChroot("/host")).Return(&ghw.BlockInfo{Disks: disks}, error).Once() + dependencies.On("Block", mock.AnythingOfType("config.Modifier")).Return(&ghw.BlockInfo{Disks: disks}, error).Once() } // mockGetPathFromDev Mocks the dependency call that try to locate the disk at /dev/diskName used by disks.getPath. diff --git a/src/inventory/system_vendor_test.go b/src/inventory/system_vendor_test.go index 8c8c43664..0f05835f5 100644 --- a/src/inventory/system_vendor_test.go +++ b/src/inventory/system_vendor_test.go @@ -9,6 +9,7 @@ import ( . "github.com/onsi/gomega" "github.com/openshift/assisted-installer-agent/src/util" "github.com/openshift/assisted-service/models" + "github.com/stretchr/testify/mock" ) var _ = Describe("System vendor test", func() { @@ -23,17 +24,17 @@ var _ = Describe("System vendor test", func() { }) It("Product error", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(nil, fmt.Errorf("Just an error")).Once() + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(nil, fmt.Errorf("Just an error")).Once() ret := GetVendor(dependencies) Expect(ret).To(Equal(&models.SystemVendor{})) }) It("Product OK", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("none", "", 0).Once() @@ -46,12 +47,12 @@ var _ = Describe("System vendor test", func() { })) }) It("Bare metal virtualization detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("none", "", 0).Once() @@ -59,12 +60,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.Virtual).ShouldNot(BeTrue()) }) It("Virtual machine detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("anyvirt", "", 0).Once() @@ -72,12 +73,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.Virtual).Should(BeTrue()) }) It("Virtual machine error on detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("", "an error", 1).Once() @@ -85,10 +86,10 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.Virtual).ShouldNot(BeTrue()) }) It("oVirt product detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Family: "oVirt", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("ovirt", "", 0).Once() @@ -100,22 +101,22 @@ var _ = Describe("System vendor test", func() { })) }) It("Chassis error", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(nil, fmt.Errorf("Just an error")).Once() + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(nil, fmt.Errorf("Just an error")).Once() ret := GetVendor(dependencies) Expect(ret).To(Equal(&models.SystemVendor{})) }) It("Oracle Cloud detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: "A Name", SerialNumber: "A Serial Number", Vendor: "A Vendor", }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "OracleCloud.com", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("none", "", 0).Once() @@ -123,12 +124,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.Manufacturer).Should(Equal("OracleCloud.com")) }) It("s390x zVM node detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: ghwutil.UNKNOWN, SerialNumber: ghwutil.UNKNOWN, Vendor: ghwutil.UNKNOWN, }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("zvm", "", 0).Once() @@ -139,12 +140,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.ProductName).Should(Equal("z/VM 7.2.0")) }) It("s390x KVM node detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: ghwutil.UNKNOWN, SerialNumber: ghwutil.UNKNOWN, Vendor: ghwutil.UNKNOWN, }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("kvm", "", 0).Once() @@ -155,12 +156,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.ProductName).Should(Equal("KVM/Linux")) }) It("s390x LPAR node detection", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: ghwutil.UNKNOWN, SerialNumber: ghwutil.UNKNOWN, Vendor: ghwutil.UNKNOWN, }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("", "", 0).Once() @@ -171,12 +172,12 @@ var _ = Describe("System vendor test", func() { Expect(systemVendor.ProductName).Should(Equal("LPAR")) }) It("s390x LPAR node detection (glitch during detect virt)", func() { - dependencies.On("Product", ghw.WithChroot("/host")).Return(&ghw.ProductInfo{ + dependencies.On("Product", mock.AnythingOfType("config.Modifier")).Return(&ghw.ProductInfo{ Name: ghwutil.UNKNOWN, SerialNumber: ghwutil.UNKNOWN, Vendor: ghwutil.UNKNOWN, }, nil).Once() - dependencies.On("Chassis", ghw.WithChroot("/host")).Return(&ghw.ChassisInfo{ + dependencies.On("Chassis", mock.AnythingOfType("config.Modifier")).Return(&ghw.ChassisInfo{ AssetTag: "An Asset Tag", }, nil).Once() dependencies.On("Execute", "systemd-detect-virt", "--vm").Return("", "an error", 1).Once() diff --git a/src/scanners/machine_uuid_scanner.go b/src/scanners/machine_uuid_scanner.go index a064f122c..36692755d 100644 --- a/src/scanners/machine_uuid_scanner.go +++ b/src/scanners/machine_uuid_scanner.go @@ -46,8 +46,8 @@ func disableGHWWarnings() { //go:generate mockery --name SerialDiscovery --inpackage type SerialDiscovery interface { - Product(opts ...*ghw.WithOption) (*ghw.ProductInfo, error) - Baseboard(opts ...*ghw.WithOption) (*ghw.BaseboardInfo, error) + Product(opts ...any) (*ghw.ProductInfo, error) + Baseboard(opts ...any) (*ghw.BaseboardInfo, error) } type GHWSerialDiscovery struct{} @@ -57,11 +57,11 @@ func NewGHWSerialDiscovery() *GHWSerialDiscovery { return &GHWSerialDiscovery{} } -func (g *GHWSerialDiscovery) Product(opts ...*ghw.WithOption) (*ghw.ProductInfo, error) { +func (g *GHWSerialDiscovery) Product(opts ...any) (*ghw.ProductInfo, error) { return ghw.Product(opts...) } -func (g *GHWSerialDiscovery) Baseboard(opts ...*ghw.WithOption) (*ghw.BaseboardInfo, error) { +func (g *GHWSerialDiscovery) Baseboard(opts ...any) (*ghw.BaseboardInfo, error) { return ghw.Baseboard(opts...) } diff --git a/src/scanners/mock_SerialDiscovery.go b/src/scanners/mock_SerialDiscovery.go index a264de898..7cd79e32f 100644 --- a/src/scanners/mock_SerialDiscovery.go +++ b/src/scanners/mock_SerialDiscovery.go @@ -6,8 +6,6 @@ import ( baseboard "github.com/jaypipes/ghw/pkg/baseboard" mock "github.com/stretchr/testify/mock" - option "github.com/jaypipes/ghw/pkg/option" - product "github.com/jaypipes/ghw/pkg/product" ) @@ -17,13 +15,9 @@ type MockSerialDiscovery struct { } // Baseboard provides a mock function with given fields: opts -func (_m *MockSerialDiscovery) Baseboard(opts ...*option.Option) (*baseboard.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockSerialDiscovery) Baseboard(opts ...interface{}) (*baseboard.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -32,10 +26,10 @@ func (_m *MockSerialDiscovery) Baseboard(opts ...*option.Option) (*baseboard.Inf var r0 *baseboard.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*baseboard.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*baseboard.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *baseboard.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *baseboard.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -43,7 +37,7 @@ func (_m *MockSerialDiscovery) Baseboard(opts ...*option.Option) (*baseboard.Inf } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -53,13 +47,9 @@ func (_m *MockSerialDiscovery) Baseboard(opts ...*option.Option) (*baseboard.Inf } // Product provides a mock function with given fields: opts -func (_m *MockSerialDiscovery) Product(opts ...*option.Option) (*product.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockSerialDiscovery) Product(opts ...interface{}) (*product.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -68,10 +58,10 @@ func (_m *MockSerialDiscovery) Product(opts ...*option.Option) (*product.Info, e var r0 *product.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*product.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*product.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *product.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *product.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -79,7 +69,7 @@ func (_m *MockSerialDiscovery) Product(opts ...*option.Option) (*product.Info, e } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) diff --git a/src/util/dependencies.go b/src/util/dependencies.go index edfa8bc31..e639e5af6 100644 --- a/src/util/dependencies.go +++ b/src/util/dependencies.go @@ -18,17 +18,17 @@ type IDependencies interface { Stat(fname string) (os.FileInfo, error) Hostname() (string, error) Interfaces() ([]Interface, error) - Block(opts ...*ghw.WithOption) (*ghw.BlockInfo, error) - Product(opts ...*ghw.WithOption) (*ghw.ProductInfo, error) + Block(opts ...any) (*ghw.BlockInfo, error) + Product(opts ...any) (*ghw.ProductInfo, error) ReadDir(dirname string) ([]os.FileInfo, error) Abs(path string) (string, error) EvalSymlinks(path string) (string, error) LinkByName(name string) (netlink.Link, error) RouteList(link netlink.Link, family int) ([]netlink.Route, error) - GPU(opts ...*ghw.WithOption) (*ghw.GPUInfo, error) - Memory(opts ...*ghw.WithOption) (*ghw.MemoryInfo, error) - Chassis(opts ...*ghw.WithOption) (*ghw.ChassisInfo, error) - PCI(opts ...*ghw.WithOption) (*ghw.PCIInfo, error) + GPU(opts ...any) (*ghw.GPUInfo, error) + Memory(opts ...any) (*ghw.MemoryInfo, error) + Chassis(opts ...any) (*ghw.ChassisInfo, error) + PCI(opts ...any) (*ghw.PCIInfo, error) GetGhwChrootRoot() string } @@ -78,11 +78,11 @@ func (d *Dependencies) Interfaces() ([]Interface, error) { return ret, nil } -func (d *Dependencies) Block(opts ...*ghw.WithOption) (*ghw.BlockInfo, error) { +func (d *Dependencies) Block(opts ...any) (*ghw.BlockInfo, error) { return ghw.Block(opts...) } -func (d *Dependencies) Product(opts ...*ghw.WithOption) (*ghw.ProductInfo, error) { +func (d *Dependencies) Product(opts ...any) (*ghw.ProductInfo, error) { return ghw.Product(opts...) } @@ -107,19 +107,19 @@ func (d *Dependencies) EvalSymlinks(path string) (string, error) { return filepath.EvalSymlinks(path) } -func (d *Dependencies) GPU(opts ...*ghw.WithOption) (*ghw.GPUInfo, error) { +func (d *Dependencies) GPU(opts ...any) (*ghw.GPUInfo, error) { return ghw.GPU(opts...) } -func (d *Dependencies) Memory(opts ...*ghw.WithOption) (*ghw.MemoryInfo, error) { +func (d *Dependencies) Memory(opts ...any) (*ghw.MemoryInfo, error) { return ghw.Memory(opts...) } -func (d *Dependencies) Chassis(opts ...*ghw.WithOption) (*ghw.ChassisInfo, error) { +func (d *Dependencies) Chassis(opts ...any) (*ghw.ChassisInfo, error) { return ghw.Chassis(opts...) } -func (d *Dependencies) PCI(opts ...*ghw.WithOption) (*ghw.PCIInfo, error) { +func (d *Dependencies) PCI(opts ...any) (*ghw.PCIInfo, error) { return ghw.PCI(opts...) } diff --git a/src/util/mock_IDependencies.go b/src/util/mock_IDependencies.go index 0ae34eee9..7f38a2726 100644 --- a/src/util/mock_IDependencies.go +++ b/src/util/mock_IDependencies.go @@ -16,8 +16,6 @@ import ( netlink "github.com/vishvananda/netlink" - option "github.com/jaypipes/ghw/pkg/option" - pci "github.com/jaypipes/ghw/pkg/pci" product "github.com/jaypipes/ghw/pkg/product" @@ -57,13 +55,9 @@ func (_m *MockIDependencies) Abs(path string) (string, error) { } // Block provides a mock function with given fields: opts -func (_m *MockIDependencies) Block(opts ...*option.Option) (*block.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) Block(opts ...interface{}) (*block.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -72,10 +66,10 @@ func (_m *MockIDependencies) Block(opts ...*option.Option) (*block.Info, error) var r0 *block.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*block.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*block.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *block.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *block.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -83,7 +77,7 @@ func (_m *MockIDependencies) Block(opts ...*option.Option) (*block.Info, error) } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -93,13 +87,9 @@ func (_m *MockIDependencies) Block(opts ...*option.Option) (*block.Info, error) } // Chassis provides a mock function with given fields: opts -func (_m *MockIDependencies) Chassis(opts ...*option.Option) (*chassis.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) Chassis(opts ...interface{}) (*chassis.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -108,10 +98,10 @@ func (_m *MockIDependencies) Chassis(opts ...*option.Option) (*chassis.Info, err var r0 *chassis.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*chassis.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*chassis.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *chassis.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *chassis.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -119,7 +109,7 @@ func (_m *MockIDependencies) Chassis(opts ...*option.Option) (*chassis.Info, err } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -241,13 +231,9 @@ func (_m *MockIDependencies) ExecutePrivileged(command string, args ...string) ( } // GPU provides a mock function with given fields: opts -func (_m *MockIDependencies) GPU(opts ...*option.Option) (*gpu.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) GPU(opts ...interface{}) (*gpu.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -256,10 +242,10 @@ func (_m *MockIDependencies) GPU(opts ...*option.Option) (*gpu.Info, error) { var r0 *gpu.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*gpu.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*gpu.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *gpu.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *gpu.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -267,7 +253,7 @@ func (_m *MockIDependencies) GPU(opts ...*option.Option) (*gpu.Info, error) { } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -383,13 +369,9 @@ func (_m *MockIDependencies) LinkByName(name string) (netlink.Link, error) { } // Memory provides a mock function with given fields: opts -func (_m *MockIDependencies) Memory(opts ...*option.Option) (*memory.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) Memory(opts ...interface{}) (*memory.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -398,10 +380,10 @@ func (_m *MockIDependencies) Memory(opts ...*option.Option) (*memory.Info, error var r0 *memory.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*memory.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*memory.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *memory.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *memory.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -409,7 +391,7 @@ func (_m *MockIDependencies) Memory(opts ...*option.Option) (*memory.Info, error } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -419,13 +401,9 @@ func (_m *MockIDependencies) Memory(opts ...*option.Option) (*memory.Info, error } // PCI provides a mock function with given fields: opts -func (_m *MockIDependencies) PCI(opts ...*option.Option) (*pci.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) PCI(opts ...interface{}) (*pci.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -434,10 +412,10 @@ func (_m *MockIDependencies) PCI(opts ...*option.Option) (*pci.Info, error) { var r0 *pci.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*pci.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*pci.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *pci.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *pci.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -445,7 +423,7 @@ func (_m *MockIDependencies) PCI(opts ...*option.Option) (*pci.Info, error) { } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) @@ -455,13 +433,9 @@ func (_m *MockIDependencies) PCI(opts ...*option.Option) (*pci.Info, error) { } // Product provides a mock function with given fields: opts -func (_m *MockIDependencies) Product(opts ...*option.Option) (*product.Info, error) { - _va := make([]interface{}, len(opts)) - for _i := range opts { - _va[_i] = opts[_i] - } +func (_m *MockIDependencies) Product(opts ...interface{}) (*product.Info, error) { var _ca []interface{} - _ca = append(_ca, _va...) + _ca = append(_ca, opts...) ret := _m.Called(_ca...) if len(ret) == 0 { @@ -470,10 +444,10 @@ func (_m *MockIDependencies) Product(opts ...*option.Option) (*product.Info, err var r0 *product.Info var r1 error - if rf, ok := ret.Get(0).(func(...*option.Option) (*product.Info, error)); ok { + if rf, ok := ret.Get(0).(func(...interface{}) (*product.Info, error)); ok { return rf(opts...) } - if rf, ok := ret.Get(0).(func(...*option.Option) *product.Info); ok { + if rf, ok := ret.Get(0).(func(...interface{}) *product.Info); ok { r0 = rf(opts...) } else { if ret.Get(0) != nil { @@ -481,7 +455,7 @@ func (_m *MockIDependencies) Product(opts ...*option.Option) (*product.Info, err } } - if rf, ok := ret.Get(1).(func(...*option.Option) error); ok { + if rf, ok := ret.Get(1).(func(...interface{}) error); ok { r1 = rf(opts...) } else { r1 = ret.Error(1) diff --git a/vendor/github.com/StackExchange/wmi/LICENSE b/vendor/github.com/StackExchange/wmi/LICENSE deleted file mode 100644 index ae80b6720..000000000 --- a/vendor/github.com/StackExchange/wmi/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Stack Exchange - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/StackExchange/wmi/README.md b/vendor/github.com/StackExchange/wmi/README.md deleted file mode 100644 index c4a432d6d..000000000 --- a/vendor/github.com/StackExchange/wmi/README.md +++ /dev/null @@ -1,13 +0,0 @@ -wmi -=== - -Package wmi provides a WQL interface to Windows WMI. - -Note: It interfaces with WMI on the local machine, therefore it only runs on Windows. - ---- - -NOTE: This project is no longer being actively maintained. If you would like -to become its new owner, please contact tlimoncelli at stack over flow dot com. - ---- diff --git a/vendor/github.com/StackExchange/wmi/swbemservices.go b/vendor/github.com/StackExchange/wmi/swbemservices.go deleted file mode 100644 index 3ff875630..000000000 --- a/vendor/github.com/StackExchange/wmi/swbemservices.go +++ /dev/null @@ -1,260 +0,0 @@ -// +build windows - -package wmi - -import ( - "fmt" - "reflect" - "runtime" - "sync" - - "github.com/go-ole/go-ole" - "github.com/go-ole/go-ole/oleutil" -) - -// SWbemServices is used to access wmi. See https://msdn.microsoft.com/en-us/library/aa393719(v=vs.85).aspx -type SWbemServices struct { - //TODO: track namespace. Not sure if we can re connect to a different namespace using the same instance - cWMIClient *Client //This could also be an embedded struct, but then we would need to branch on Client vs SWbemServices in the Query method - sWbemLocatorIUnknown *ole.IUnknown - sWbemLocatorIDispatch *ole.IDispatch - queries chan *queryRequest - closeError chan error - lQueryorClose sync.Mutex -} - -type queryRequest struct { - query string - dst interface{} - args []interface{} - finished chan error -} - -// InitializeSWbemServices will return a new SWbemServices object that can be used to query WMI -func InitializeSWbemServices(c *Client, connectServerArgs ...interface{}) (*SWbemServices, error) { - //fmt.Println("InitializeSWbemServices: Starting") - //TODO: implement connectServerArgs as optional argument for init with connectServer call - s := new(SWbemServices) - s.cWMIClient = c - s.queries = make(chan *queryRequest) - initError := make(chan error) - go s.process(initError) - - err, ok := <-initError - if ok { - return nil, err //Send error to caller - } - //fmt.Println("InitializeSWbemServices: Finished") - return s, nil -} - -// Close will clear and release all of the SWbemServices resources -func (s *SWbemServices) Close() error { - s.lQueryorClose.Lock() - if s == nil || s.sWbemLocatorIDispatch == nil { - s.lQueryorClose.Unlock() - return fmt.Errorf("SWbemServices is not Initialized") - } - if s.queries == nil { - s.lQueryorClose.Unlock() - return fmt.Errorf("SWbemServices has been closed") - } - //fmt.Println("Close: sending close request") - var result error - ce := make(chan error) - s.closeError = ce //Race condition if multiple callers to close. May need to lock here - close(s.queries) //Tell background to shut things down - s.lQueryorClose.Unlock() - err, ok := <-ce - if ok { - result = err - } - //fmt.Println("Close: finished") - return result -} - -func (s *SWbemServices) process(initError chan error) { - //fmt.Println("process: starting background thread initialization") - //All OLE/WMI calls must happen on the same initialized thead, so lock this goroutine - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - err := ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) - if err != nil { - oleCode := err.(*ole.OleError).Code() - if oleCode != ole.S_OK && oleCode != S_FALSE { - initError <- fmt.Errorf("ole.CoInitializeEx error: %v", err) - return - } - } - defer ole.CoUninitialize() - - unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator") - if err != nil { - initError <- fmt.Errorf("CreateObject SWbemLocator error: %v", err) - return - } else if unknown == nil { - initError <- ErrNilCreateObject - return - } - defer unknown.Release() - s.sWbemLocatorIUnknown = unknown - - dispatch, err := s.sWbemLocatorIUnknown.QueryInterface(ole.IID_IDispatch) - if err != nil { - initError <- fmt.Errorf("SWbemLocator QueryInterface error: %v", err) - return - } - defer dispatch.Release() - s.sWbemLocatorIDispatch = dispatch - - // we can't do the ConnectServer call outside the loop unless we find a way to track and re-init the connectServerArgs - //fmt.Println("process: initialized. closing initError") - close(initError) - //fmt.Println("process: waiting for queries") - for q := range s.queries { - //fmt.Printf("process: new query: len(query)=%d\n", len(q.query)) - errQuery := s.queryBackground(q) - //fmt.Println("process: s.queryBackground finished") - if errQuery != nil { - q.finished <- errQuery - } - close(q.finished) - } - //fmt.Println("process: queries channel closed") - s.queries = nil //set channel to nil so we know it is closed - //TODO: I think the Release/Clear calls can panic if things are in a bad state. - //TODO: May need to recover from panics and send error to method caller instead. - close(s.closeError) -} - -// Query runs the WQL query using a SWbemServices instance and appends the values to dst. -// -// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in -// the query must have the same name in dst. Supported types are all signed and -// unsigned integers, time.Time, string, bool, or a pointer to one of those. -// Array types are not supported. -// -// By default, the local machine and default namespace are used. These can be -// changed using connectServerArgs. See -// http://msdn.microsoft.com/en-us/library/aa393720.aspx for details. -func (s *SWbemServices) Query(query string, dst interface{}, connectServerArgs ...interface{}) error { - s.lQueryorClose.Lock() - if s == nil || s.sWbemLocatorIDispatch == nil { - s.lQueryorClose.Unlock() - return fmt.Errorf("SWbemServices is not Initialized") - } - if s.queries == nil { - s.lQueryorClose.Unlock() - return fmt.Errorf("SWbemServices has been closed") - } - - //fmt.Println("Query: Sending query request") - qr := queryRequest{ - query: query, - dst: dst, - args: connectServerArgs, - finished: make(chan error), - } - s.queries <- &qr - s.lQueryorClose.Unlock() - err, ok := <-qr.finished - if ok { - //fmt.Println("Query: Finished with error") - return err //Send error to caller - } - //fmt.Println("Query: Finished") - return nil -} - -func (s *SWbemServices) queryBackground(q *queryRequest) error { - if s == nil || s.sWbemLocatorIDispatch == nil { - return fmt.Errorf("SWbemServices is not Initialized") - } - wmi := s.sWbemLocatorIDispatch //Should just rename in the code, but this will help as we break things apart - //fmt.Println("queryBackground: Starting") - - dv := reflect.ValueOf(q.dst) - if dv.Kind() != reflect.Ptr || dv.IsNil() { - return ErrInvalidEntityType - } - dv = dv.Elem() - mat, elemType := checkMultiArg(dv) - if mat == multiArgTypeInvalid { - return ErrInvalidEntityType - } - - // service is a SWbemServices - serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer", q.args...) - if err != nil { - return err - } - service := serviceRaw.ToIDispatch() - defer serviceRaw.Clear() - - // result is a SWBemObjectSet - resultRaw, err := oleutil.CallMethod(service, "ExecQuery", q.query) - if err != nil { - return err - } - result := resultRaw.ToIDispatch() - defer resultRaw.Clear() - - count, err := oleInt64(result, "Count") - if err != nil { - return err - } - - enumProperty, err := result.GetProperty("_NewEnum") - if err != nil { - return err - } - defer enumProperty.Clear() - - enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant) - if err != nil { - return err - } - if enum == nil { - return fmt.Errorf("can't get IEnumVARIANT, enum is nil") - } - defer enum.Release() - - // Initialize a slice with Count capacity - dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count))) - - var errFieldMismatch error - for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) { - if err != nil { - return err - } - - err := func() error { - // item is a SWbemObject, but really a Win32_Process - item := itemRaw.ToIDispatch() - defer item.Release() - - ev := reflect.New(elemType) - if err = s.cWMIClient.loadEntity(ev.Interface(), item); err != nil { - if _, ok := err.(*ErrFieldMismatch); ok { - // We continue loading entities even in the face of field mismatch errors. - // If we encounter any other error, that other error is returned. Otherwise, - // an ErrFieldMismatch is returned. - errFieldMismatch = err - } else { - return err - } - } - if mat != multiArgTypeStructPtr { - ev = ev.Elem() - } - dv.Set(reflect.Append(dv, ev)) - return nil - }() - if err != nil { - return err - } - } - //fmt.Println("queryBackground: Finished") - return errFieldMismatch -} diff --git a/vendor/github.com/StackExchange/wmi/wmi.go b/vendor/github.com/StackExchange/wmi/wmi.go deleted file mode 100644 index b4bb4f090..000000000 --- a/vendor/github.com/StackExchange/wmi/wmi.go +++ /dev/null @@ -1,590 +0,0 @@ -// +build windows - -/* -Package wmi provides a WQL interface for WMI on Windows. - -Example code to print names of running processes: - - type Win32_Process struct { - Name string - } - - func main() { - var dst []Win32_Process - q := wmi.CreateQuery(&dst, "") - err := wmi.Query(q, &dst) - if err != nil { - log.Fatal(err) - } - for i, v := range dst { - println(i, v.Name) - } - } - -*/ -package wmi - -import ( - "bytes" - "errors" - "fmt" - "log" - "os" - "reflect" - "runtime" - "strconv" - "strings" - "sync" - "time" - - "github.com/go-ole/go-ole" - "github.com/go-ole/go-ole/oleutil" -) - -var l = log.New(os.Stdout, "", log.LstdFlags) - -var ( - ErrInvalidEntityType = errors.New("wmi: invalid entity type") - // ErrNilCreateObject is the error returned if CreateObject returns nil even - // if the error was nil. - ErrNilCreateObject = errors.New("wmi: create object returned nil") - lock sync.Mutex -) - -// S_FALSE is returned by CoInitializeEx if it was already called on this thread. -const S_FALSE = 0x00000001 - -// QueryNamespace invokes Query with the given namespace on the local machine. -func QueryNamespace(query string, dst interface{}, namespace string) error { - return Query(query, dst, nil, namespace) -} - -// Query runs the WQL query and appends the values to dst. -// -// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in -// the query must have the same name in dst. Supported types are all signed and -// unsigned integers, time.Time, string, bool, or a pointer to one of those. -// Array types are not supported. -// -// By default, the local machine and default namespace are used. These can be -// changed using connectServerArgs. See -// https://docs.microsoft.com/en-us/windows/desktop/WmiSdk/swbemlocator-connectserver -// for details. -// -// Query is a wrapper around DefaultClient.Query. -func Query(query string, dst interface{}, connectServerArgs ...interface{}) error { - if DefaultClient.SWbemServicesClient == nil { - return DefaultClient.Query(query, dst, connectServerArgs...) - } - return DefaultClient.SWbemServicesClient.Query(query, dst, connectServerArgs...) -} - -// CallMethod calls a method named methodName on an instance of the class named -// className, with the given params. -// -// CallMethod is a wrapper around DefaultClient.CallMethod. -func CallMethod(connectServerArgs []interface{}, className, methodName string, params []interface{}) (int32, error) { - return DefaultClient.CallMethod(connectServerArgs, className, methodName, params) -} - -// A Client is an WMI query client. -// -// Its zero value (DefaultClient) is a usable client. -type Client struct { - // NonePtrZero specifies if nil values for fields which aren't pointers - // should be returned as the field types zero value. - // - // Setting this to true allows stucts without pointer fields to be used - // without the risk failure should a nil value returned from WMI. - NonePtrZero bool - - // PtrNil specifies if nil values for pointer fields should be returned - // as nil. - // - // Setting this to true will set pointer fields to nil where WMI - // returned nil, otherwise the types zero value will be returned. - PtrNil bool - - // AllowMissingFields specifies that struct fields not present in the - // query result should not result in an error. - // - // Setting this to true allows custom queries to be used with full - // struct definitions instead of having to define multiple structs. - AllowMissingFields bool - - // SWbemServiceClient is an optional SWbemServices object that can be - // initialized and then reused across multiple queries. If it is null - // then the method will initialize a new temporary client each time. - SWbemServicesClient *SWbemServices -} - -// DefaultClient is the default Client and is used by Query, QueryNamespace, and CallMethod. -var DefaultClient = &Client{} - -// coinitService coinitializes WMI service. If no error is returned, a cleanup function -// is returned which must be executed (usually deferred) to clean up allocated resources. -func (c *Client) coinitService(connectServerArgs ...interface{}) (*ole.IDispatch, func(), error) { - var unknown *ole.IUnknown - var wmi *ole.IDispatch - var serviceRaw *ole.VARIANT - - // be sure teardown happens in the reverse - // order from that which they were created - deferFn := func() { - if serviceRaw != nil { - serviceRaw.Clear() - } - if wmi != nil { - wmi.Release() - } - if unknown != nil { - unknown.Release() - } - ole.CoUninitialize() - } - - // if we error'ed here, clean up immediately - var err error - defer func() { - if err != nil { - deferFn() - } - }() - - err = ole.CoInitializeEx(0, ole.COINIT_MULTITHREADED) - if err != nil { - oleCode := err.(*ole.OleError).Code() - if oleCode != ole.S_OK && oleCode != S_FALSE { - return nil, nil, err - } - } - - unknown, err = oleutil.CreateObject("WbemScripting.SWbemLocator") - if err != nil { - return nil, nil, err - } else if unknown == nil { - return nil, nil, ErrNilCreateObject - } - - wmi, err = unknown.QueryInterface(ole.IID_IDispatch) - if err != nil { - return nil, nil, err - } - - // service is a SWbemServices - serviceRaw, err = oleutil.CallMethod(wmi, "ConnectServer", connectServerArgs...) - if err != nil { - return nil, nil, err - } - - return serviceRaw.ToIDispatch(), deferFn, nil -} - -// CallMethod calls a WMI method named methodName on an instance -// of the class named className. It passes in the arguments given -// in params. Use connectServerArgs to customize the machine and -// namespace; by default, the local machine and default namespace -// are used. See -// https://docs.microsoft.com/en-us/windows/desktop/WmiSdk/swbemlocator-connectserver -// for details. -func (c *Client) CallMethod(connectServerArgs []interface{}, className, methodName string, params []interface{}) (int32, error) { - service, cleanup, err := c.coinitService(connectServerArgs...) - if err != nil { - return 0, fmt.Errorf("coinit: %v", err) - } - defer cleanup() - - // Get class - classRaw, err := oleutil.CallMethod(service, "Get", className) - if err != nil { - return 0, fmt.Errorf("CallMethod Get class %s: %v", className, err) - } - class := classRaw.ToIDispatch() - defer classRaw.Clear() - - // Run method - resultRaw, err := oleutil.CallMethod(class, methodName, params...) - if err != nil { - return 0, fmt.Errorf("CallMethod %s.%s: %v", className, methodName, err) - } - resultInt, ok := resultRaw.Value().(int32) - if !ok { - return 0, fmt.Errorf("return value was not an int32: %v (%T)", resultRaw, resultRaw) - } - - return resultInt, nil -} - -// Query runs the WQL query and appends the values to dst. -// -// dst must have type *[]S or *[]*S, for some struct type S. Fields selected in -// the query must have the same name in dst. Supported types are all signed and -// unsigned integers, time.Time, string, bool, or a pointer to one of those. -// Array types are not supported. -// -// By default, the local machine and default namespace are used. These can be -// changed using connectServerArgs. See -// https://docs.microsoft.com/en-us/windows/desktop/WmiSdk/swbemlocator-connectserver -// for details. -func (c *Client) Query(query string, dst interface{}, connectServerArgs ...interface{}) error { - dv := reflect.ValueOf(dst) - if dv.Kind() != reflect.Ptr || dv.IsNil() { - return ErrInvalidEntityType - } - dv = dv.Elem() - mat, elemType := checkMultiArg(dv) - if mat == multiArgTypeInvalid { - return ErrInvalidEntityType - } - - lock.Lock() - defer lock.Unlock() - runtime.LockOSThread() - defer runtime.UnlockOSThread() - - service, cleanup, err := c.coinitService(connectServerArgs...) - if err != nil { - return err - } - defer cleanup() - - // result is a SWBemObjectSet - resultRaw, err := oleutil.CallMethod(service, "ExecQuery", query) - if err != nil { - return err - } - result := resultRaw.ToIDispatch() - defer resultRaw.Clear() - - count, err := oleInt64(result, "Count") - if err != nil { - return err - } - - enumProperty, err := result.GetProperty("_NewEnum") - if err != nil { - return err - } - defer enumProperty.Clear() - - enum, err := enumProperty.ToIUnknown().IEnumVARIANT(ole.IID_IEnumVariant) - if err != nil { - return err - } - if enum == nil { - return fmt.Errorf("can't get IEnumVARIANT, enum is nil") - } - defer enum.Release() - - // Initialize a slice with Count capacity - dv.Set(reflect.MakeSlice(dv.Type(), 0, int(count))) - - var errFieldMismatch error - for itemRaw, length, err := enum.Next(1); length > 0; itemRaw, length, err = enum.Next(1) { - if err != nil { - return err - } - - err := func() error { - // item is a SWbemObject, but really a Win32_Process - item := itemRaw.ToIDispatch() - defer item.Release() - - ev := reflect.New(elemType) - if err = c.loadEntity(ev.Interface(), item); err != nil { - if _, ok := err.(*ErrFieldMismatch); ok { - // We continue loading entities even in the face of field mismatch errors. - // If we encounter any other error, that other error is returned. Otherwise, - // an ErrFieldMismatch is returned. - errFieldMismatch = err - } else { - return err - } - } - if mat != multiArgTypeStructPtr { - ev = ev.Elem() - } - dv.Set(reflect.Append(dv, ev)) - return nil - }() - if err != nil { - return err - } - } - return errFieldMismatch -} - -// ErrFieldMismatch is returned when a field is to be loaded into a different -// type than the one it was stored from, or when a field is missing or -// unexported in the destination struct. -// StructType is the type of the struct pointed to by the destination argument. -type ErrFieldMismatch struct { - StructType reflect.Type - FieldName string - Reason string -} - -func (e *ErrFieldMismatch) Error() string { - return fmt.Sprintf("wmi: cannot load field %q into a %q: %s", - e.FieldName, e.StructType, e.Reason) -} - -var timeType = reflect.TypeOf(time.Time{}) - -// loadEntity loads a SWbemObject into a struct pointer. -func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismatch error) { - v := reflect.ValueOf(dst).Elem() - for i := 0; i < v.NumField(); i++ { - f := v.Field(i) - of := f - isPtr := f.Kind() == reflect.Ptr - if isPtr { - ptr := reflect.New(f.Type().Elem()) - f.Set(ptr) - f = f.Elem() - } - n := v.Type().Field(i).Name - if n[0] < 'A' || n[0] > 'Z' { - continue - } - if !f.CanSet() { - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "CanSet() is false", - } - } - prop, err := oleutil.GetProperty(src, n) - if err != nil { - if !c.AllowMissingFields { - errFieldMismatch = &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "no such struct field", - } - } - continue - } - defer prop.Clear() - - if prop.VT == 0x1 { //VT_NULL - continue - } - - switch val := prop.Value().(type) { - case int8, int16, int32, int64, int: - v := reflect.ValueOf(val).Int() - switch f.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - f.SetInt(v) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - f.SetUint(uint64(v)) - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "not an integer class", - } - } - case uint8, uint16, uint32, uint64: - v := reflect.ValueOf(val).Uint() - switch f.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - f.SetInt(int64(v)) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - f.SetUint(v) - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "not an integer class", - } - } - case string: - switch f.Kind() { - case reflect.String: - f.SetString(val) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - iv, err := strconv.ParseInt(val, 10, 64) - if err != nil { - return err - } - f.SetInt(iv) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - uv, err := strconv.ParseUint(val, 10, 64) - if err != nil { - return err - } - f.SetUint(uv) - case reflect.Struct: - switch f.Type() { - case timeType: - if len(val) == 25 { - mins, err := strconv.Atoi(val[22:]) - if err != nil { - return err - } - val = val[:22] + fmt.Sprintf("%02d%02d", mins/60, mins%60) - } - t, err := time.Parse("20060102150405.000000-0700", val) - if err != nil { - return err - } - f.Set(reflect.ValueOf(t)) - } - } - case bool: - switch f.Kind() { - case reflect.Bool: - f.SetBool(val) - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "not a bool", - } - } - case float32: - switch f.Kind() { - case reflect.Float32: - f.SetFloat(float64(val)) - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: "not a Float32", - } - } - default: - if f.Kind() == reflect.Slice { - switch f.Type().Elem().Kind() { - case reflect.String: - safeArray := prop.ToArray() - if safeArray != nil { - arr := safeArray.ToValueArray() - fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr)) - for i, v := range arr { - s := fArr.Index(i) - s.SetString(v.(string)) - } - f.Set(fArr) - } - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - safeArray := prop.ToArray() - if safeArray != nil { - arr := safeArray.ToValueArray() - fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr)) - for i, v := range arr { - s := fArr.Index(i) - s.SetUint(reflect.ValueOf(v).Uint()) - } - f.Set(fArr) - } - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: - safeArray := prop.ToArray() - if safeArray != nil { - arr := safeArray.ToValueArray() - fArr := reflect.MakeSlice(f.Type(), len(arr), len(arr)) - for i, v := range arr { - s := fArr.Index(i) - s.SetInt(reflect.ValueOf(v).Int()) - } - f.Set(fArr) - } - default: - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: fmt.Sprintf("unsupported slice type (%T)", val), - } - } - } else { - typeof := reflect.TypeOf(val) - if typeof == nil && (isPtr || c.NonePtrZero) { - if (isPtr && c.PtrNil) || (!isPtr && c.NonePtrZero) { - of.Set(reflect.Zero(of.Type())) - } - break - } - return &ErrFieldMismatch{ - StructType: of.Type(), - FieldName: n, - Reason: fmt.Sprintf("unsupported type (%T)", val), - } - } - } - } - return errFieldMismatch -} - -type multiArgType int - -const ( - multiArgTypeInvalid multiArgType = iota - multiArgTypeStruct - multiArgTypeStructPtr -) - -// checkMultiArg checks that v has type []S, []*S for some struct type S. -// -// It returns what category the slice's elements are, and the reflect.Type -// that represents S. -func checkMultiArg(v reflect.Value) (m multiArgType, elemType reflect.Type) { - if v.Kind() != reflect.Slice { - return multiArgTypeInvalid, nil - } - elemType = v.Type().Elem() - switch elemType.Kind() { - case reflect.Struct: - return multiArgTypeStruct, elemType - case reflect.Ptr: - elemType = elemType.Elem() - if elemType.Kind() == reflect.Struct { - return multiArgTypeStructPtr, elemType - } - } - return multiArgTypeInvalid, nil -} - -func oleInt64(item *ole.IDispatch, prop string) (int64, error) { - v, err := oleutil.GetProperty(item, prop) - if err != nil { - return 0, err - } - defer v.Clear() - - i := int64(v.Val) - return i, nil -} - -// CreateQuery returns a WQL query string that queries all columns of src. where -// is an optional string that is appended to the query, to be used with WHERE -// clauses. In such a case, the "WHERE" string should appear at the beginning. -// The wmi class is obtained by the name of the type. You can pass a optional -// class throught the variadic class parameter which is useful for anonymous -// structs. -func CreateQuery(src interface{}, where string, class ...string) string { - var b bytes.Buffer - b.WriteString("SELECT ") - s := reflect.Indirect(reflect.ValueOf(src)) - t := s.Type() - if s.Kind() == reflect.Slice { - t = t.Elem() - } - if t.Kind() != reflect.Struct { - return "" - } - var fields []string - for i := 0; i < t.NumField(); i++ { - fields = append(fields, t.Field(i).Name) - } - b.WriteString(strings.Join(fields, ", ")) - b.WriteString(" FROM ") - if len(class) > 0 { - b.WriteString(class[0]) - } else { - b.WriteString(t.Name()) - } - b.WriteString(" " + where) - return b.String() -} diff --git a/vendor/github.com/jaypipes/ghw/.gitignore b/vendor/github.com/jaypipes/ghw/.gitignore index 34d0d840a..a155166d3 100644 --- a/vendor/github.com/jaypipes/ghw/.gitignore +++ b/vendor/github.com/jaypipes/ghw/.gitignore @@ -1,3 +1,4 @@ vendor/ coverage*.* *~ +bin/ diff --git a/vendor/github.com/jaypipes/ghw/Makefile b/vendor/github.com/jaypipes/ghw/Makefile index 75d2bcc8b..b55e9dfbf 100644 --- a/vendor/github.com/jaypipes/ghw/Makefile +++ b/vendor/github.com/jaypipes/ghw/Makefile @@ -1,16 +1,35 @@ -.PHONY: test +VERSION ?= $(shell git describe --tags --always --dirty) + +.PHONY: test clean vet fmt fmtcheck build run + +bin/ghwc: + @cd cmd/ghwc && go build -o ../../bin/ghwc main.go && cd ../../ + +# If the first argument is "run"... +ifeq (run,$(firstword $(MAKECMDGOALS))) + # use the rest as arguments for "run" + RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) + # ...and turn them into do-nothing targets + $(eval $(RUN_ARGS):;@:) +endif + +build: clean bin/ghwc + +run: build + @bin/ghwc $(RUN_ARGS) + test: vet go test -v ./... -.PHONY: fmt fmt: @echo "Running gofmt on all sources..." @gofmt -s -l -w . -.PHONY: fmtcheck fmtcheck: @bash -c "diff -u <(echo -n) <(gofmt -d .)" -.PHONY: vet vet: go vet ./... + +clean: + @rm -f bin/ghwc diff --git a/vendor/github.com/jaypipes/ghw/README.md b/vendor/github.com/jaypipes/ghw/README.md index bad7c86e1..a5f5b06ce 100644 --- a/vendor/github.com/jaypipes/ghw/README.md +++ b/vendor/github.com/jaypipes/ghw/README.md @@ -14,7 +14,7 @@ Windows. There currently exists partial support for MacOSX. * No root privileges needed for discovery - `ghw` goes the extra mile to be useful without root priveleges. We query for + `ghw` goes the extra mile to be useful without root privileges. We query for host hardware information as directly as possible without relying on shellouts to programs like `dmidecode` that require root privileges to execute. @@ -345,8 +345,8 @@ Each `ghw.Partition` struct contains these fields: * `ghw.Partition.IsReadOnly` is a bool indicating the partition is read-only * `ghw.Partition.Disk` is a pointer to the `ghw.Disk` object associated with the partition. -* `ghw.Partition.UUID` is a string containing the partition UUID on Linux, the - partition UUID on MacOS and nothing on Windows. On Linux systems, this is +* `ghw.Partition.UUID` is a string containing the partition UUID on Linux and MacOS, + and the `VolumeSerialNumber` on Windows (e.g. "A8C3D032"). On Linux systems, this is derived from the `ID_PART_ENTRY_UUID` [udev][udev] entry for the partition. [udev]: https://en.wikipedia.org/wiki/Udev @@ -520,7 +520,7 @@ information about the host computer's networking hardware. The `ghw.NetworkInfo` struct contains one field: * `ghw.NetworkInfo.NICs` is an array of pointers to `ghw.NIC` structs, one - for each network interface controller found for the systen + for each network interface controller found for the system Each `ghw.NIC` struct contains the following fields: @@ -1206,17 +1206,12 @@ feature to quiet things down. ### Disabling warning messages When `ghw` isn't able to retrieve some information, it may print certain -warning messages to `stderr`. To disable these warnings, simply set the +warning messages to `stderr`. To disable these warnings, set the `GHW_DISABLE_WARNINGS` environs variable: ``` $ ghwc memory -WARNING: -Could not determine total physical bytes of memory. This may -be due to the host being a virtual machine or container with no -/var/log/syslog file, or the current user may not have necessary -privileges to read the syslog. We are falling back to setting the -total physical amount of memory to the total usable amount of memory +WARN: Could not determine total physical bytes of memory. This may be due to the host being a virtual machine or container with no /var/log/syslog file, or the current user may not have necessary privileges to read the syslog. We are falling back to setting the total physical amount of memory to the total usable amount of memory memory (24GB physical, 24GB usable) ``` @@ -1225,10 +1220,10 @@ $ GHW_DISABLE_WARNINGS=1 ghwc memory memory (24GB physical, 24GB usable) ``` -You can disable warning programmatically using the `WithDisableWarnings` option: +You can disable warning programmatically using the `WithDisableWarnings` +modifier: ```go - import ( "github.com/jaypipes/ghw" ) @@ -1236,14 +1231,172 @@ import ( mem, err := ghw.Memory(ghw.WithDisableWarnings()) ``` -`WithDisableWarnings` is a alias for the `WithNullAlerter` option, which in turn -leverages the more general `Alerter` feature of ghw. +### Controlling log output + +The default log output in `ghw` only writes WARN-level messages to `stderr` in +a simple `WARN: ` log record format: + +``` +$ ghwc baseboard +WARN: Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied +baseboard vendor=System76 version=thelio-mira-b4.1 product=Thelio Mira +``` + +You can control a number of log output options programmatically or by using +environs variables. + +#### Change the log level + +To change the log level `ghw` uses, set the `GHW_LOG_LEVEL` environs variable: + +``` +$ GHW_LOG_LEVEL=debug ghwc baseboard +DEBUG: reading from "/sys/class/dmi/id/board_asset_tag" +DEBUG: reading from "/sys/class/dmi/id/board_serial" +WARN: Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied +DEBUG: reading from "/sys/class/dmi/id/board_vendor" +DEBUG: reading from "/sys/class/dmi/id/board_version" +DEBUG: reading from "/sys/class/dmi/id/board_name" +baseboard vendor=System76 version=thelio-mira-b4.1 product=Thelio Mira +``` + +Changing `GHW_LOG_LEVEL` to `error` has the same effect of setting +`GHW_DISABLE_WARNINGS`: + +``` +$ GHW_LOG_LEVEL=error ghwc baseboard +baseboard vendor=System76 version=thelio-mira-b4.1 product=Thelio Mira +``` + +You can change the log level programmatically using the `WithLogLevel` +modifier: + +```go +import ( + "log/slog" + + "github.com/jaypipes/ghw" +) + +bb, err := ghw.Baseboard(ghw.WithLogLevel(slog.LevelDebug)) +``` + +#### Use logfmt output format + +To use the [logfmt][logfmt] standard log output format, set the +`GHW_LOG_LOGFMT` envrions variable: + +``` +$ GHW_LOG_LOGFMT=1 ghwc baseboard +time=2025-12-28T07:31:08.614-05:00 level=WARN msg="Unable to read board_serial: open /sys/class/dmi/id/board_serial: permission denied" +baseboard vendor=System76 version=thelio-mira-b4.1 product=Thelio Mira +``` + +You can tell `ghw` to use `logfmt` standard output formatting using the `WithLogLogfmt` +modifier: + +```go +import ( + "log/slog" + + "github.com/jaypipes/ghw" +) + +bb, err := ghw.Baseboard(ghw.WithLogLogfmt()) +``` + +[logfmt]: https://www.cloudbees.com/blog/logfmt-a-log-format-thats-easy-to-read-and-write + +#### Provide a custom logger + +You can programmatically override the logger that `ghw` uses with the +`WithLogger` modifier. You pass in an instance of `slog.Logger`, like this +example that shows how to use a simple logger with colored log output: + +```go +package main + +import ( + "context" + "encoding/json" + "io" + "log" + "log/slog" + + "github.com/fatih/color" + "github.com/jaypipes/ghw" +) + +type PrettyHandlerOptions struct { + SlogOpts slog.HandlerOptions +} + +type PrettyHandler struct { + slog.Handler + l *log.Logger +} + +func (h *PrettyHandler) Handle(ctx context.Context, r slog.Record) error { + level := r.Level.String() + ":" + + switch r.Level { + case slog.LevelDebug: + level = color.MagentaString(level) + case slog.LevelInfo: + level = color.BlueString(level) + case slog.LevelWarn: + level = color.YellowString(level) + case slog.LevelError: + level = color.RedString(level) + } + + fields := make(map[string]any, r.NumAttrs()) + r.Attrs(func(a slog.Attr) bool { + fields[a.Key] = a.Value.Any() + + return true + }) + + b, err := json.MarshalIndent(fields, "", " ") + if err != nil { + return err + } + + timeStr := r.Time.Format("[15:05:05.000]") + msg := color.CyanString(r.Message) + + h.l.Println(timeStr, level, msg, color.WhiteString(string(b))) + + return nil +} + +func NewPrettyHandler( + out io.Writer, + opts PrettyHandlerOptions, +) *PrettyHandler { + h := &PrettyHandler{ + Handler: slog.NewJSONHandler(out, &opts.SlogOpts), + l: log.New(out, "", 0), + } -You may supply a `Alerter` to ghw to redirect all the warnings there, like -logger objects (see for example golang's stdlib `log.Logger`). -`Alerter` is in fact the minimal logging interface `ghw needs. -To learn more, please check the `option.Alerter` interface and the `ghw.WithAlerter()` -function. + return h +} + +func main() { + opts := PrettyHandlerOptions{ + SlogOpts: slog.HandlerOptions{ + Level: slog.LevelDebug, + }, + } + handler := NewPrettyHandler(os.Stdout, opts) + logger := slog.New(handler) + bb, err := ghw.Baseboard(ghw.WithLogger(logger)) + if err != nil { + logger.Error(err.String()) + } + fmt.Println(bb) +} +``` ### Overriding the root mountpoint `ghw` uses @@ -1332,59 +1485,75 @@ cpu, err := ghw.CPU(ghw.WithPathOverrides(ghw.PathOverrides{ ### Reading hardware information from a `ghw` snapshot (Linux only) -The `ghw-snapshot` tool can create a snapshot of a host's hardware information. - -Please read [`SNAPSHOT.md`](SNAPSHOT.md) to learn about creating snapshots with -the `ghw-snapshot` tool. - -You can make `ghw` read hardware information from a snapshot created with -`ghw-snapshot` using environment variables or programmatically. - -Use the `GHW_SNAPSHOT_PATH` environment variable to specify the filepath to a -snapshot that `ghw` will read to determine hardware information. All the needed -chroot changes will be automatically performed. By default, the snapshot is -unpacked into a temporary directory managed by `ghw`. This temporary directory -is automatically deleted when `ghw` is finished reading the snapshot. +The `ghwc snapshot` command creates a snapshot of a host's hardware information. -Three other environment variables are relevant if and only if `GHW_SNAPSHOT_PATH` -is not empty: +Use the `ghwc -s` flag to supply a path to a snapshot to read with the `ghwc` +command-line program. -* `GHW_SNAPSHOT_ROOT` let users specify the directory on which the snapshot - should be unpacked. This moves the ownership of that directory from `ghw` to - users. For this reason, `ghw` will *not* automatically clean up the content - unpacked into `GHW_SNAPSHOT_ROOT`. -* `GHW_SNAPSHOT_EXCLUSIVE` tells `ghw` that the directory is meant only to - contain the given snapshot, thus `ghw` will *not* attempt to unpack it unless - the directory is empty. You can use both `GHW_SNAPSHOT_ROOT` and - `GHW_SNAPSHOT_EXCLUSIVE` to make sure `ghw` unpacks the snapshot only once - regardless of how many `ghw` packages (e.g. cpu, memory) access it. Set the - value of this environment variable to any non-empty string. -* `GHW_SNAPSHOT_PRESERVE` tells `ghw` not to clean up the unpacked snapshot. - Set the value of this environment variable to any non-empty string. - -```go -cpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{ - Path: "/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz", -})) - - -myRoot := "/my/safe/directory" -cpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{ - Path: "/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz", - Root: &myRoot, -})) - -myOtherRoot := "/my/other/safe/directory" -cpu, err := ghw.CPU(ghw.WithSnapshot(ghw.SnapshotOptions{ - Path: "/path/to/linux-amd64-d4771ed3300339bc75f856be09fc6430.tar.gz", - Root: &myOtherRoot, - Exclusive: true, -})) +``` +$ ghwc -s testdata/snapshots/linux-amd64-amd-ryzen-1600.tar.gz +block storage (8 disks, 3TB physical storage) + dm-0 SSD (90GB) Unknown [@unknown (node #0)] vendor=unknown + dm-1 Unknown (16GB) Unknown [@unknown (node #0)] vendor=unknown + dm-2 SSD (60GB) Unknown [@unknown (node #0)] vendor=unknown + dm-3 SSD (13GB) Unknown [@unknown (node #0)] vendor=unknown + dm-4 SSD (436GB) Unknown [@unknown (node #0)] vendor=unknown + sda SSD (239GB) SCSI [@unknown (node #0)] vendor=unknown + sda1 (128MB) [unknown] + sda2 (384MB) [unknown] + sda3 (238GB) [unknown] + sdb HDD (932GB) SCSI [@unknown (node #0)] vendor=unknown + sdb1 (2GB) [unknown] + sdb2 (930GB) [unknown] + sdc SSD (466GB) SCSI [@unknown (node #0)] vendor=unknown + sdc1 (32GB) [unknown] + sdc2 (434GB) [unknown] +cpu (1 physical package, 6 cores, 12 hardware threads) + physical package #0 (6 cores, 12 hardware threads) + processor core #0 (2 threads), logical processors [0 6] + processor core #1 (2 threads), logical processors [1 7] + processor core #5 (2 threads), logical processors [4 10] + processor core #6 (2 threads), logical processors [5 11] + processor core #2 (2 threads), logical processors [2 8] + processor core #4 (2 threads), logical processors [3 9] + capabilities: [msr pae mce cx8 apic sep + mtrr pge mca cmov pat pse36 + clflush mmx fxsr sse sse2 ht + syscall nx mmxext fxsr_opt pdpe1gb rdtscp + lm constant_tsc art rep_good nopl nonstop_tsc + extd_apicid aperfmperf eagerfpu pni pclmulqdq monitor + ssse3 fma cx16 sse4_1 sse4_2 movbe + popcnt aes xsave avx f16c rdrand + lahf_lm cmp_legacy svm extapic cr8_legacy abm + sse4a misalignsse 3dnowprefetch osvw skinit wdt + tce topoext perfctr_core perfctr_nb bpext perfctr_l2 + hw_pstate sme retpoline_amd ssbd ibpb vmmcall + fsgsbase bmi1 avx2 smep bmi2 rdseed + adx smap clflushopt sha_ni xsaveopt xsavec + xgetbv1 clzero irperf xsaveerptr arat npt + lbrv svm_lock nrip_save tsc_scale vmcb_clean flushbyasid + decodeassists pausefilter pfthreshold avic v_vmsave_vmload vgif + overflow_recov succor smca] +gpu (1 graphics card) + card #0 @0000:0a:00.0 -> driver: '' class: 'Display controller' vendor: 'Advanced Micro Devices, Inc. [AMD/ATI]' product: 'Turks XT [Radeon HD 6670/7670]' +processing accelerators (0 devices) +memory (32GB physical, 32GB usable) +net (4 NICs) + enp3s0 + enp6s0f0 + enp6s0f1 + enp8s0 +topology NUMA (0 nodes) +chassis type=unknown vendor=unknown version=unknown +bios vendor=unknown version=unknown +baseboard vendor=unknown version=unknown product=unknown +product family=unknown name=unknown vendor=unknown sku=unknown version=unknown +PCI (43 devices) ``` ### Creating snapshots -You can create `ghw` snapshots using the `ghw-snapshot` tool or +You can create `ghw` snapshots using the `ghwc snapshot` command or programmatically using the `pkg/snapshot` package. Below is an example of creating a `ghw` snapshot using the `pkg/snapshot` diff --git a/vendor/github.com/jaypipes/ghw/SNAPSHOT.md b/vendor/github.com/jaypipes/ghw/SNAPSHOT.md index 696a3ea63..ddd815741 100644 --- a/vendor/github.com/jaypipes/ghw/SNAPSHOT.md +++ b/vendor/github.com/jaypipes/ghw/SNAPSHOT.md @@ -7,10 +7,11 @@ the paths ghw cares about. The snapshot concept was introduced [to make ghw easi ## Create and consume snapshot -The recommended way to create snapshots for ghw is to use the `ghw-snapshot` tool. +The recommended way to create snapshots for ghw is to use the `ghwc snapshot` command. + This tool is maintained by the ghw authors, and snapshots created with this tool are guaranteed to work. -To consume the ghw snapshots, please check the `README.md` document. +To display hardware information from a ghw snapshot, use the `ghwc -s` flag, passing the filepath to the snapshot to use. ## Snapshot design and definitions @@ -21,10 +22,6 @@ expect, we recommend to check also the [project issues](https://github.com/jaypi ### Scope ghw supports snapshots only on linux platforms. This restriction may be lifted in future releases. -Snapshots must be consumable in the following supported ways: - -1. (way 1) from docker (or podman), mounting them as volumes. See `hack/run-against-snapshot.sh` -2. (way 2) using the environment variables `GHW_SNAPSHOT_*`. See `README.md` for the full documentation. Other combinations are possible, but are unsupported and may stop working any time. You should depend only on the supported ways to consume snapshots. @@ -42,4 +39,3 @@ Stemming from the use cases, the snapshot content must have the following proper It must be noted that trivially cloning subtrees from `/proc` and `/sys` and creating a tarball out of them doesn't work because both pseudo filesystems make use of symlinks, and [docker doesn't really play nice with symlinks](https://github.com/jaypipes/ghw/commit/f8ffd4d24e62eb9017511f072ccf51f13d4a3399). This conflcits with (way 1) above. - diff --git a/vendor/github.com/jaypipes/ghw/alias.go b/vendor/github.com/jaypipes/ghw/alias.go index 9c403d969..83c5fd538 100644 --- a/vendor/github.com/jaypipes/ghw/alias.go +++ b/vendor/github.com/jaypipes/ghw/alias.go @@ -7,6 +7,7 @@ package ghw import ( + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/accelerator" "github.com/jaypipes/ghw/pkg/baseboard" "github.com/jaypipes/ghw/pkg/bios" @@ -21,24 +22,27 @@ import ( pciaddress "github.com/jaypipes/ghw/pkg/pci/address" "github.com/jaypipes/ghw/pkg/product" "github.com/jaypipes/ghw/pkg/topology" + "github.com/jaypipes/ghw/pkg/usb" ) -type WithOption = option.Option - var ( - WithChroot = option.WithChroot - WithSnapshot = option.WithSnapshot - WithAlerter = option.WithAlerter - WithNullAlerter = option.WithNullAlerter - // match the existing environ variable to minimize surprises - WithDisableWarnings = option.WithNullAlerter - WithDisableTools = option.WithDisableTools - WithPathOverrides = option.WithPathOverrides -) + ContextFromEnv = config.ContextFromEnv -type SnapshotOptions = option.SnapshotOptions + WithChroot = config.WithChroot + // DEPRECATED: Please use WithLogger + WithAlerter = option.WithAlerter + // DEPRECATED: Please use WithDisableWarnings + WithNullAlerter = option.WithNullAlerter + WithDisableWarnings = config.WithDisableWarnings + WithDisableTools = config.WithDisableTools + WithDisableTopology = config.WithDisableTopology + WithPathOverrides = config.WithPathOverrides + WithLogLevel = config.WithLogLevel + WithDebug = config.WithDebug + WithLogger = config.WithLogger +) -type PathOverrides = option.PathOverrides +type PathOverrides map[string]string type CPUInfo = cpu.Info @@ -68,6 +72,10 @@ var ( Memory = memory.New ) +var ( + USB = usb.New +) + type BlockInfo = block.Info type Disk = block.Disk type Partition = block.Partition diff --git a/vendor/github.com/jaypipes/ghw/host.go b/vendor/github.com/jaypipes/ghw/host.go index 89b1ad277..9c76b172f 100644 --- a/vendor/github.com/jaypipes/ghw/host.go +++ b/vendor/github.com/jaypipes/ghw/host.go @@ -9,8 +9,7 @@ package ghw import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" - + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/accelerator" "github.com/jaypipes/ghw/pkg/baseboard" "github.com/jaypipes/ghw/pkg/bios" @@ -24,12 +23,12 @@ import ( "github.com/jaypipes/ghw/pkg/pci" "github.com/jaypipes/ghw/pkg/product" "github.com/jaypipes/ghw/pkg/topology" + "github.com/jaypipes/ghw/pkg/usb" ) // HostInfo is a wrapper struct containing information about the host system's // memory, block storage, CPU, etc type HostInfo struct { - ctx *context.Context Memory *memory.Info `json:"memory"` Block *block.Info `json:"block"` CPU *cpu.Info `json:"cpu"` @@ -42,63 +41,67 @@ type HostInfo struct { Baseboard *baseboard.Info `json:"baseboard"` Product *product.Info `json:"product"` PCI *pci.Info `json:"pci"` + USB *usb.Info `json:"usb"` } // Host returns a pointer to a HostInfo struct that contains fields with // information about the host system's CPU, memory, network devices, etc -func Host(opts ...*WithOption) (*HostInfo, error) { - ctx := context.New(opts...) - - memInfo, err := memory.New(opts...) +func Host(args ...any) (*HostInfo, error) { + ctx := config.ContextFromArgs(args...) + memInfo, err := memory.New(ctx) + if err != nil { + return nil, err + } + blockInfo, err := block.New(ctx) if err != nil { return nil, err } - blockInfo, err := block.New(opts...) + cpuInfo, err := cpu.New(ctx) if err != nil { return nil, err } - cpuInfo, err := cpu.New(opts...) + topologyInfo, err := topology.New(ctx) if err != nil { return nil, err } - topologyInfo, err := topology.New(opts...) + netInfo, err := net.New(ctx) if err != nil { return nil, err } - netInfo, err := net.New(opts...) + gpuInfo, err := gpu.New(ctx) if err != nil { return nil, err } - gpuInfo, err := gpu.New(opts...) + acceleratorInfo, err := accelerator.New(ctx) if err != nil { return nil, err } - acceleratorInfo, err := accelerator.New(opts...) + chassisInfo, err := chassis.New(ctx) if err != nil { return nil, err } - chassisInfo, err := chassis.New(opts...) + biosInfo, err := bios.New(ctx) if err != nil { return nil, err } - biosInfo, err := bios.New(opts...) + baseboardInfo, err := baseboard.New(ctx) if err != nil { return nil, err } - baseboardInfo, err := baseboard.New(opts...) + productInfo, err := product.New(ctx) if err != nil { return nil, err } - productInfo, err := product.New(opts...) + pciInfo, err := pci.New(ctx) if err != nil { return nil, err } - pciInfo, err := pci.New(opts...) + usbInfo, err := usb.New(ctx) if err != nil { return nil, err } + return &HostInfo{ - ctx: ctx, CPU: cpuInfo, Memory: memInfo, Block: blockInfo, @@ -111,6 +114,7 @@ func Host(opts ...*WithOption) (*HostInfo, error) { Baseboard: baseboardInfo, Product: productInfo, PCI: pciInfo, + USB: usbInfo, }, nil } @@ -118,7 +122,7 @@ func Host(opts ...*WithOption) (*HostInfo, error) { // structs' String-ified output func (info *HostInfo) String() string { return fmt.Sprintf( - "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", info.Block.String(), info.CPU.String(), info.GPU.String(), @@ -131,17 +135,18 @@ func (info *HostInfo) String() string { info.Baseboard.String(), info.Product.String(), info.PCI.String(), + info.USB.String(), ) } // YAMLString returns a string with the host information formatted as YAML // under a top-level "host:" key func (i *HostInfo) YAMLString() string { - return marshal.SafeYAML(i.ctx, i) + return marshal.SafeYAML(i) } // JSONString returns a string with the host information formatted as JSON // under a top-level "host:" key func (i *HostInfo) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, i, indent) + return marshal.SafeJSON(i, indent) } diff --git a/vendor/github.com/jaypipes/ghw/internal/config/context.go b/vendor/github.com/jaypipes/ghw/internal/config/context.go new file mode 100644 index 000000000..72a7a0e8d --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/internal/config/context.go @@ -0,0 +1,235 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package config + +import ( + "context" + "os" + + "github.com/jaypipes/ghw/pkg/option" + "github.com/jaypipes/pcidb" +) + +const ( + envKeyChroot = "GHW_CHROOT" + envKeyDisableWarnings = "GHW_DISABLE_WARNINGS" + envKeyDisableTools = "GHW_DISABLE_TOOLS" + envKeyDisableTopology = "GHW_DISABLE_TOPOLOGY" +) + +type Key string + +var ( + defaultChroot = "/" + chrootKey = Key("ghw.chroot") + defaultToolsEnabled = true + toolsEnabledKey = Key("ghw.tools.enabled") + defaultTopologyEnabled = true + topologyEnabledKey = Key("ghw.topology.enabled") + pcidbKey = Key("ghw.pcidb") + pathOverridesKey = Key("ghw.path.overrides") +) + +// Modifier sets some value on the context +type Modifier func(context.Context) context.Context + +// WithChroot allows overriding the root directory ghw examines. +func WithChroot(path string) Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, chrootKey, path) + } +} + +// Chroot gets a context's chroot override or the default if none is set. +func Chroot(ctx context.Context) string { + if ctx == nil { + return defaultChroot + } + if v := ctx.Value(chrootKey); v != nil { + return v.(string) + } + return defaultChroot +} + +// EnvOrDefaultChroot returns the value of the GHW_CHROOT environs variable or +// the default value of "/" if not set +func EnvOrDefaultChroot() string { + // Grab options from the environs by default + if val, exists := os.LookupEnv(envKeyChroot); exists { + return val + } + return defaultChroot +} + +// WithDisableTools prevents ghw from calling external tools to discover +// hardware capabilities. +func WithDisableTools() Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, toolsEnabledKey, false) + } +} + +// ToolsEnabled returns true if external tools have been disabled. +func ToolsEnabled(ctx context.Context) bool { + if ctx == nil { + return defaultToolsEnabled + } + if v := ctx.Value(toolsEnabledKey); v != nil { + return v.(bool) + } + return defaultToolsEnabled +} + +// EnvOrDefaultDisableTools return true if ghw should use external tools to +// augment the data collected from sysfs. Most users want to do this most of +// time, so this is enabled by default. Users consuming snapshots may want to +// opt out, thus they can set the GHW_DISABLE_TOOLS environs variable to any +// value to make ghw skip calling external tools even if they are available. +func EnvOrDefaultDisableTools() bool { + if _, exists := os.LookupEnv(envKeyDisableTools); exists { + return true + } + return false +} + +// WithDisableTopology disables system topology detection to reduce memory +// consumption. When using this option, ghw will skip scanning NUMA topology, +// CPU cores, memory caches, and node distances. This is useful when you only +// need basic PCI or GPU information and want to minimize memory overhead. The +// system architecture will be assumed to be SMP, and device Node fields will +// be nil. +func WithDisableTopology() Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, topologyEnabledKey, false) + } +} + +// EnvOrDefaultEnableTopology return true if ghw should detect system topology. +func EnvOrDefaultEnableTopology() bool { + if _, exists := os.LookupEnv(envKeyDisableTopology); exists { + return false + } + return defaultTopologyEnabled +} + +// TopologyEnabled returns true if the detection of system topology is enabled. +func TopologyEnabled(ctx context.Context) bool { + if ctx == nil { + return defaultTopologyEnabled + } + if v := ctx.Value(topologyEnabledKey); v != nil { + return v.(bool) + } + return defaultTopologyEnabled +} + +// WithPCIDB allows you to provide a custom instance of the PCI database +// (pcidb.PCIDB) to ghw. This is useful if you want to use a preloaded or +// specially configured PCI database, such as one created with custom +// pcidb.WithOption settings, instead of letting ghw load the PCI database +// automatically. +func WithPCIDB(db *pcidb.PCIDB) Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, pcidbKey, db) + } +} + +// PCIDB returns any PCIDB pointer set in the supplied context. +func PCIDB(ctx context.Context) *pcidb.PCIDB { + if ctx == nil { + return nil + } + if v := ctx.Value(pcidbKey); v != nil { + return v.(*pcidb.PCIDB) + } + return nil +} + +// WithPathOverrides supplies path-specific overrides for the context +func WithPathOverrides(overrides map[string]string) Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, pathOverridesKey, overrides) + } +} + +// PathOverrides returns any path overrides set in the supplied context. +func PathOverrides(ctx context.Context) map[string]string { + if ctx == nil { + return nil + } + if v := ctx.Value(pathOverridesKey); v != nil { + return v.(map[string]string) + } + return nil +} + +// ContextFromEnv returns a new context.Context populated from the environs or +// default option values +func ContextFromEnv() context.Context { + ctx := context.TODO() + ctx = context.WithValue(ctx, chrootKey, EnvOrDefaultChroot()) + ctx = context.WithValue(ctx, toolsEnabledKey, EnvOrDefaultDisableTools()) + ll := EnvOrDefaultLogLevel() + logLevelVar.Set(ll) + ctx = context.WithValue(ctx, logLevelKey, ll) + disableWarn := EnvOrDefaultDisableWarnings() + if disableWarn { + ctx = WithDisableWarnings()(ctx) + } + useLogfmt := EnvOrDefaultLogLogfmt() + if useLogfmt { + ctx = WithLogLogfmt()(ctx) + } + return ctx +} + +// fromOptions converts old-style pkg/option.Options by setting any Options +// fields on the supplied context. +// +// TODO(jaypipes): Remove this when we fully deprecate the old-style +// pkg/options stuff. +func fromOptions(ctx context.Context, opts *option.Options) context.Context { + if opts == nil { + return ctx + } + if opts.Chroot != "" { + ctx = context.WithValue(ctx, chrootKey, opts.Chroot) + } + if opts.DisableTools { + ctx = context.WithValue(ctx, toolsEnabledKey, false) + } + if opts.PCIDB != nil { + ctx = context.WithValue(ctx, pcidbKey, opts.PCIDB) + } + if opts.PathOverrides != nil { + ctx = context.WithValue(ctx, pathOverridesKey, opts.PathOverrides) + } + return ctx +} + +// ContextFromArgs returns a context.Context populated with any old-style +// options or new-style arguments. +func ContextFromArgs(args ...any) context.Context { + ctx := context.TODO() + optsUsed := false + opts := &option.Options{} + for _, arg := range args { + switch arg := arg.(type) { + case context.Context: + ctx = arg + case Modifier: + ctx = arg(ctx) + case option.Option: + arg(opts) + optsUsed = true + } + } + if optsUsed { + ctx = fromOptions(ctx, opts) + } + return ctx +} diff --git a/vendor/github.com/jaypipes/ghw/internal/config/log.go b/vendor/github.com/jaypipes/ghw/internal/config/log.go new file mode 100644 index 000000000..3ae156c83 --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/internal/config/log.go @@ -0,0 +1,156 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package config + +import ( + "context" + "log" + "log/slog" + "os" + "strings" +) + +const ( + envKeyLogLevel = "GHW_LOG_LEVEL" + envKeyLogLogfmt = "GHW_LOG_LOGFMT" +) + +var ( + logLevelKey = Key("ghw.log.level") + defaultLogLevel = slog.LevelWarn + logLevelVar = new(slog.LevelVar) + loggerKey = Key("ghw.logger") + logfmtLogger = slog.New( + slog.NewTextHandler( + os.Stderr, + &slog.HandlerOptions{ + Level: logLevelVar, + }, + ), + ) + defaultLogger = slog.New( + &simpleHandler{ + Handler: slog.NewTextHandler( + os.Stderr, + &slog.HandlerOptions{ + Level: logLevelVar, + }, + ), + l: log.New(os.Stderr, "", 0), + }, + ) +) + +// simpleHandler is a custom log handler meant to emulate the experience ghw had +// before we moved to log/slog. It implements log/slog.Handler. +type simpleHandler struct { + slog.Handler + l *log.Logger +} + +func (h *simpleHandler) Handle( + ctx context.Context, + r slog.Record, +) error { + level := r.Level.String() + ":" + + h.l.Printf("%-6s %s", level, r.Message) + + return nil +} + +// WithLogLevel allows overriding the default log level of WARN. +func WithLogLevel(level slog.Level) Modifier { + return func(ctx context.Context) context.Context { + logLevelVar.Set(level) + return context.WithValue(ctx, logLevelKey, level) + } +} + +// WithLogLogfmt sets the log output to the logfmt standard. +func WithLogLogfmt() Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, loggerKey, logfmtLogger) + } +} + +// EnvOrDefaultLogLogfmt return true if ghw should use logfmt standard output +// format based on the GHW_LOG_LOGFMT environs variable. +func EnvOrDefaultLogLogfmt() bool { + if _, exists := os.LookupEnv(envKeyLogLogfmt); exists { + return true + } + return false +} + +// WithLogger allows overriding the default logger +func WithLogger(logger *slog.Logger) Modifier { + return func(ctx context.Context) context.Context { + return context.WithValue(ctx, loggerKey, logger) + } +} + +// LogLevel gets a context's logger's log level or the default if none is set. +func LogLevel(ctx context.Context) slog.Level { + if ctx == nil { + return defaultLogLevel + } + if v := ctx.Value(logLevelKey); v != nil { + return v.(slog.Level) + } + return defaultLogLevel +} + +// EnvOrDefaultLogLevel return true if ghw should not output warnings +// based on the GHW_LOG_LEVEL environs variable. +func EnvOrDefaultLogLevel() slog.Level { + if ll, exists := os.LookupEnv(envKeyLogLevel); exists { + switch strings.ToLower(ll) { + case "debug": + return slog.LevelDebug + case "info": + return slog.LevelInfo + case "warn", "warning": + return slog.LevelWarn + case "err", "error": + return slog.LevelError + default: + return defaultLogLevel + } + } + return defaultLogLevel +} + +// Logger gets a context's logger override or the default if none is set. +func Logger(ctx context.Context) *slog.Logger { + if ctx == nil { + return defaultLogger + } + if v := ctx.Value(loggerKey); v != nil { + return v.(*slog.Logger) + } + return defaultLogger +} + +// WithDebug enables verbose debugging output. +func WithDebug() Modifier { + return WithLogLevel(slog.LevelDebug) +} + +// WithDisableWarnings tells ghw not to output warning messages. +func WithDisableWarnings() Modifier { + return WithLogLevel(slog.LevelError) +} + +// EnvOrDefaultDisableWarnings return true if ghw should not output warnings +// based on the GHW_DISABLE_WARNINGS environs variable. +func EnvOrDefaultDisableWarnings() bool { + if _, exists := os.LookupEnv(envKeyDisableWarnings); exists { + return true + } + return false +} diff --git a/vendor/github.com/jaypipes/ghw/internal/log/log.go b/vendor/github.com/jaypipes/ghw/internal/log/log.go new file mode 100644 index 000000000..3fdad94ec --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/internal/log/log.go @@ -0,0 +1,57 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package log + +import ( + "context" + "fmt" + "log/slog" + "runtime" + "strings" + "time" + + "github.com/jaypipes/ghw/internal/config" +) + +// Info outputs an INFO-level log message to the logger configured in the +// supplied context. +func Info(ctx context.Context, format string, args ...any) { + logger := config.Logger(ctx) + if logger == nil || !logger.Enabled(ctx, slog.LevelInfo) { + return + } + var stack [1]uintptr + runtime.Callers(2, stack[:]) // skip [Callers, Info] + r := slog.NewRecord(time.Now(), slog.LevelInfo, strings.TrimSpace(fmt.Sprintf(format, args...)), stack[0]) + _ = logger.Handler().Handle(ctx, r) +} + +// Warn outputs an WARN-level log message to the logger configured in the +// supplied context. +func Warn(ctx context.Context, format string, args ...any) { + logger := config.Logger(ctx) + if logger == nil || !logger.Enabled(ctx, slog.LevelWarn) { + return + } + var stack [1]uintptr + runtime.Callers(2, stack[:]) // skip [Callers, Warn] + r := slog.NewRecord(time.Now(), slog.LevelWarn, strings.TrimSpace(fmt.Sprintf(format, args...)), stack[0]) + _ = logger.Handler().Handle(ctx, r) +} + +// Debug outputs an DEBUG-level log message to the logger configured in the +// supplied context. +func Debug(ctx context.Context, format string, args ...any) { + logger := config.Logger(ctx) + if logger == nil || !logger.Enabled(ctx, slog.LevelDebug) { + return + } + var stack [1]uintptr + runtime.Callers(2, stack[:]) // skip [Callers, Debug] + r := slog.NewRecord(time.Now(), slog.LevelDebug, strings.TrimSpace(fmt.Sprintf(format, args...)), stack[0]) + _ = logger.Handler().Handle(ctx, r) +} diff --git a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator.go b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator.go index b51ef2e21..c7dbc62fc 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator.go +++ b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator.go @@ -9,9 +9,8 @@ package accelerator import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/pci" ) @@ -37,17 +36,15 @@ func (dev *AcceleratorDevice) String() string { } type Info struct { - ctx *context.Context Devices []*AcceleratorDevice `json:"devices"` } // New returns a pointer to an Info struct that contains information about the // accelerator devices on the host system -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -59,7 +56,7 @@ func (i *Info) String() string { numDevsStr = "device" } return fmt.Sprintf( - "processing accelerators (%d %s)", + "accelerators (%d %s)", len(i.Devices), numDevsStr, ) @@ -74,11 +71,11 @@ type acceleratorPrinter struct { // YAMLString returns a string with the processing accelerators information formatted as YAML // under a top-level "accelerator:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, acceleratorPrinter{i}) + return marshal.SafeYAML(acceleratorPrinter{i}) } // JSONString returns a string with the processing accelerators information formatted as JSON // under a top-level "accelerator:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, acceleratorPrinter{i}, indent) + return marshal.SafeJSON(acceleratorPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_linux.go b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_linux.go index 39d7eecb6..68df54158 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_linux.go @@ -6,7 +6,9 @@ package accelerator import ( - "github.com/jaypipes/ghw/pkg/context" + "context" + + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/pci" ) @@ -31,13 +33,13 @@ var ( } ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { accelDevices := make([]*AcceleratorDevice, 0) // get PCI devices - pciInfo, err := pci.New(context.WithContext(i.ctx)) + pciInfo, err := pci.New(ctx) if err != nil { - i.ctx.Warn("error loading PCI information: %s", err) + log.Warn(ctx, "error loading PCI information: %s", err) return nil } diff --git a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_stub.go b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_stub.go index 7e0b9fd4e..07929d17d 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_stub.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux && !windows +// +build !linux,!windows // Use and distribution licensed under the Apache license version 2. // @@ -9,11 +9,12 @@ package accelerator import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("accelerator.Info.load not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_windows.go b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_windows.go new file mode 100644 index 000000000..c2cf56d34 --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/pkg/accelerator/accelerator_windows.go @@ -0,0 +1,13 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package accelerator + +import "context" + +func (i *Info) load(ctx context.Context) error { + i.Devices = []*AcceleratorDevice{} + return nil +} diff --git a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard.go b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard.go index ac4bf41a9..681f4fbee 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard.go +++ b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard.go @@ -7,15 +7,13 @@ package baseboard import ( - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/util" ) // Info defines baseboard release information type Info struct { - ctx *context.Context AssetTag string `json:"asset_tag"` SerialNumber string `json:"serial_number"` Vendor string `json:"vendor"` @@ -52,10 +50,10 @@ func (i *Info) String() string { // New returns a pointer to an Info struct containing information about the // host's baseboard -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -70,11 +68,11 @@ type baseboardPrinter struct { // YAMLString returns a string with the baseboard information formatted as YAML // under a top-level "dmi:" key func (info *Info) YAMLString() string { - return marshal.SafeYAML(info.ctx, baseboardPrinter{info}) + return marshal.SafeYAML(baseboardPrinter{info}) } // JSONString returns a string with the baseboard information formatted as JSON // under a top-level "baseboard:" key func (info *Info) JSONString(indent bool) string { - return marshal.SafeJSON(info.ctx, baseboardPrinter{info}, indent) + return marshal.SafeJSON(baseboardPrinter{info}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_linux.go b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_linux.go index c8c598d42..86f3986b7 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_linux.go @@ -6,15 +6,17 @@ package baseboard import ( + "context" + "github.com/jaypipes/ghw/pkg/linuxdmi" ) -func (i *Info) load() error { - i.AssetTag = linuxdmi.Item(i.ctx, "board_asset_tag") - i.SerialNumber = linuxdmi.Item(i.ctx, "board_serial") - i.Vendor = linuxdmi.Item(i.ctx, "board_vendor") - i.Version = linuxdmi.Item(i.ctx, "board_version") - i.Product = linuxdmi.Item(i.ctx, "board_name") +func (i *Info) load(ctx context.Context) error { + i.AssetTag = linuxdmi.Item(ctx, "board_asset_tag") + i.SerialNumber = linuxdmi.Item(ctx, "board_serial") + i.Vendor = linuxdmi.Item(ctx, "board_vendor") + i.Version = linuxdmi.Item(ctx, "board_version") + i.Product = linuxdmi.Item(ctx, "board_name") return nil } diff --git a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_stub.go b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_stub.go index f5b146919..e2a3c5f75 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_stub.go @@ -9,11 +9,12 @@ package baseboard import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("baseboardFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_windows.go b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_windows.go index 0fb14fbff..c0a36f704 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/baseboard/baseboard_windows.go @@ -6,7 +6,9 @@ package baseboard import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" ) const wqlBaseboard = "SELECT Manufacturer, SerialNumber, Tag, Version, Product FROM Win32_BaseBoard" @@ -19,7 +21,7 @@ type win32Baseboard struct { Product *string } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting data from WMI var win32BaseboardDescriptions []win32Baseboard if err := wmi.Query(wqlBaseboard, &win32BaseboardDescriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/bios/bios.go b/vendor/github.com/jaypipes/ghw/pkg/bios/bios.go index 85a7c64b1..0961dc3c1 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/bios/bios.go +++ b/vendor/github.com/jaypipes/ghw/pkg/bios/bios.go @@ -9,15 +9,13 @@ package bios import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/util" ) // Info defines BIOS release information type Info struct { - ctx *context.Context Vendor string `json:"vendor"` Version string `json:"version"` Date string `json:"date"` @@ -49,10 +47,10 @@ func (i *Info) String() string { // New returns a pointer to a Info struct containing information // about the host's BIOS -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -67,11 +65,11 @@ type biosPrinter struct { // YAMLString returns a string with the BIOS information formatted as YAML // under a top-level "dmi:" key func (info *Info) YAMLString() string { - return marshal.SafeYAML(info.ctx, biosPrinter{info}) + return marshal.SafeYAML(biosPrinter{info}) } // JSONString returns a string with the BIOS information formatted as JSON // under a top-level "bios:" key func (info *Info) JSONString(indent bool) string { - return marshal.SafeJSON(info.ctx, biosPrinter{info}, indent) + return marshal.SafeJSON(biosPrinter{info}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_linux.go b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_linux.go index 9788f4f7a..1305f10c1 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_linux.go @@ -5,12 +5,16 @@ package bios -import "github.com/jaypipes/ghw/pkg/linuxdmi" +import ( + "context" -func (i *Info) load() error { - i.Vendor = linuxdmi.Item(i.ctx, "bios_vendor") - i.Version = linuxdmi.Item(i.ctx, "bios_version") - i.Date = linuxdmi.Item(i.ctx, "bios_date") + "github.com/jaypipes/ghw/pkg/linuxdmi" +) + +func (i *Info) load(ctx context.Context) error { + i.Vendor = linuxdmi.Item(ctx, "bios_vendor") + i.Version = linuxdmi.Item(ctx, "bios_version") + i.Date = linuxdmi.Item(ctx, "bios_date") return nil } diff --git a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_stub.go b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_stub.go index 5307b4a0a..5e9f25da7 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_stub.go @@ -9,11 +9,12 @@ package bios import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("biosFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_windows.go b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_windows.go index 778628e9a..e688e1051 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/bios/bios_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/bios/bios_windows.go @@ -6,7 +6,9 @@ package bios import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" ) const wqlBIOS = "SELECT InstallDate, Manufacturer, Version FROM CIM_BIOSElement" @@ -17,7 +19,7 @@ type win32BIOS struct { Version *string } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting data from WMI var win32BIOSDescriptions []win32BIOS if err := wmi.Query(wqlBIOS, &win32BIOSDescriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/block/block.go b/vendor/github.com/jaypipes/ghw/pkg/block/block.go index 5e75eea6f..9e2ec766f 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/block/block.go +++ b/vendor/github.com/jaypipes/ghw/pkg/block/block.go @@ -13,9 +13,8 @@ import ( "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/unitutil" "github.com/jaypipes/ghw/pkg/util" ) @@ -251,7 +250,7 @@ type Disk struct { type Partition struct { // Disk is a pointer to the `Disk` struct that houses this partition. Disk *Disk `json:"-"` - // Name is the system name given to the partition, e.g. "sda1". + // Name is the system given or user given name to the partition, e.g. "sda1". Name string `json:"name"` // Label is the human-readable label given to the partition. On Linux, this // is derived from the `ID_PART_ENTRY_NAME` udev entry. @@ -265,8 +264,9 @@ type Partition struct { Type string `json:"type"` // IsReadOnly indicates if the partition is marked read-only. IsReadOnly bool `json:"read_only"` - // UUID is the universally-unique identifier (UUID) for the partition. - // This will be volume UUID on Darwin, PartUUID on linux, empty on Windows. + // UUID is a unique identifier for the partition. Note that for Windows + // partitions, this field contains a Volume Serial Number which is not + // in the standard UUID format, e.g. "A8C3D032". UUID string `json:"uuid"` // FilesystemLabel is the label of the filesystem contained on the // partition. On Linux, this is derived from the `ID_FS_NAME` udev entry. @@ -275,7 +275,6 @@ type Partition struct { // Info describes all disk drives and partitions in the host system. type Info struct { - ctx *context.Context // TotalSizeBytes contains the total amount of storage, in bytes, on the // host system. TotalSizeBytes uint64 `json:"total_size_bytes"` @@ -291,10 +290,10 @@ type Info struct { // New returns a pointer to an Info struct that describes the block storage // resources of the host system. -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -406,11 +405,11 @@ type blockPrinter struct { // YAMLString returns a string with the block information formatted as YAML // under a top-level "block:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, blockPrinter{i}) + return marshal.SafeYAML(blockPrinter{i}) } // JSONString returns a string with the block information formatted as JSON // under a top-level "block:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, blockPrinter{i}, indent) + return marshal.SafeJSON(blockPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/block/block_darwin.go b/vendor/github.com/jaypipes/ghw/pkg/block/block_darwin.go index c6b6c2664..0ce52b88f 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/block/block_darwin.go +++ b/vendor/github.com/jaypipes/ghw/pkg/block/block_darwin.go @@ -6,6 +6,7 @@ package block import ( + "context" "fmt" "os" "os/exec" @@ -14,6 +15,8 @@ import ( "github.com/pkg/errors" "howett.net/plist" + + "github.com/jaypipes/ghw/internal/config" ) type diskOrPartitionPlistNode struct { @@ -146,7 +149,11 @@ func getIoregPlist(ioDeviceTreePath string) (*ioregPlist, error) { return nil, errors.Wrapf(err, "ioreg unmarshal for %q failed", ioDeviceTreePath) } if len(data) != 1 { - err := errors.Errorf("ioreg unmarshal resulted in %d I/O device tree nodes (expected 1)", len(data)) + err := errors.Errorf( + "ioreg unmarshal resulted in %d I/O device tree nodes "+ + "for path %q (expected 1)", + len(data), ioDeviceTreePath, + ) return nil, err } @@ -206,9 +213,9 @@ func storageControllerFromPlist(infoPlist *diskUtilInfoPlist) StorageController return sc } -func (info *Info) load() error { - if !info.ctx.EnableTools { - return fmt.Errorf("EnableTools=false on darwin disables block support entirely.") +func (info *Info) load(ctx context.Context) error { + if !config.ToolsEnabled(ctx) { + return fmt.Errorf("DisableTools=true on darwin disables block support entirely.") } listPlist, err := getDiskUtilListPlist() diff --git a/vendor/github.com/jaypipes/ghw/pkg/block/block_linux.go b/vendor/github.com/jaypipes/ghw/pkg/block/block_linux.go index 3542bd72c..c6298bc14 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/block/block_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/block/block_linux.go @@ -7,13 +7,14 @@ package block import ( "bufio" + "context" "io" "os" "path/filepath" "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/util" ) @@ -22,9 +23,8 @@ const ( sectorSize = 512 ) -func (i *Info) load() error { - paths := linuxpath.New(i.ctx) - i.Disks = disks(i.ctx, paths) +func (i *Info) load(ctx context.Context) error { + i.Disks = disks(ctx) var tsb uint64 for _, d := range i.Disks { tsb += d.SizeBytes @@ -219,12 +219,16 @@ func diskWWN(paths *linuxpath.Paths, disk string) string { // but just the name. In other words, "sda", not "/dev/sda" and "nvme0n1" not // "/dev/nvme0n1") and returns a slice of pointers to Partition structs // representing the partitions in that disk -func diskPartitions(ctx *context.Context, paths *linuxpath.Paths, disk string) []*Partition { +func diskPartitions( + ctx context.Context, + paths *linuxpath.Paths, + disk string, +) []*Partition { out := make([]*Partition, 0) path := filepath.Join(paths.SysBlock, disk) files, err := os.ReadDir(path) if err != nil { - ctx.Warn("failed to read disk partitions: %s\n", err) + log.Warn(ctx, "failed to read disk partitions: %s\n", err) return out } for _, file := range files { @@ -315,7 +319,8 @@ func diskIsRemovable(paths *linuxpath.Paths, disk string) bool { return removable == "1" } -func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { +func disks(ctx context.Context) []*Disk { + paths := linuxpath.New(ctx) // In Linux, we could use the fdisk, lshw or blockdev commands to list disk // information, however all of these utilities require root privileges to // run. We can get all of this information by examining the /sys/block @@ -331,7 +336,10 @@ func disks(ctx *context.Context, paths *linuxpath.Paths) []*Disk { driveType, storageController := diskTypes(dname) // TODO(jaypipes): Move this into diskTypes() once abstracting // diskIsRotational for ease of unit testing - if !diskIsRotational(ctx, paths, dname) { + // Only reclassify HDD to SSD if non-rotational to avoid changing already correct types. + // This addresses changed kernel behavior where rotational detection may be unreliable, + // where some kernels report CD-ROM drives as non-rotational, incorrectly classifying them as SSD. + if !diskIsRotational(ctx, paths, dname) && driveType == DRIVE_TYPE_HDD { driveType = DRIVE_TYPE_SSD } size := diskSizeBytes(paths, dname) @@ -419,7 +427,11 @@ func diskTypes(dname string) ( return driveType, storageController } -func diskIsRotational(ctx *context.Context, paths *linuxpath.Paths, devName string) bool { +func diskIsRotational( + ctx context.Context, + paths *linuxpath.Paths, + devName string, +) bool { path := filepath.Join(paths.SysBlock, devName, "queue", "rotational") contents := util.SafeIntFromFile(ctx, path) return contents == 1 diff --git a/vendor/github.com/jaypipes/ghw/pkg/block/block_stub.go b/vendor/github.com/jaypipes/ghw/pkg/block/block_stub.go index f5b516455..f398b1850 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/block/block_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/block/block_stub.go @@ -9,11 +9,12 @@ package block import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(_ context.Context) error { return errors.New("blockFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/block/block_windows.go b/vendor/github.com/jaypipes/ghw/pkg/block/block_windows.go index 270e19f98..cb7330a3c 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/block/block_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/block/block_windows.go @@ -6,10 +6,11 @@ package block import ( + "context" "strconv" "strings" - "github.com/StackExchange/wmi" + "github.com/yusufpapurcu/wmi" "github.com/jaypipes/ghw/pkg/util" ) @@ -85,18 +86,20 @@ type win32LogicalDiskToPartition struct { Dependent *string } -const wqlLogicalDisk = "SELECT Caption, CreationClassName, Description, DeviceID, FileSystem, FreeSpace, Name, Size, SystemName FROM Win32_LogicalDisk" +const wqlLogicalDisk = "SELECT Caption, CreationClassName, Description, DeviceID, FileSystem, FreeSpace, Name, Size, SystemName, VolumeName, VolumeSerialNumber FROM Win32_LogicalDisk" type win32LogicalDisk struct { - Caption *string - CreationClassName *string - Description *string - DeviceID *string - FileSystem *string - FreeSpace *uint64 - Name *string - Size *uint64 - SystemName *string + Caption *string + CreationClassName *string + Description *string + DeviceID *string + FileSystem *string + FreeSpace *uint64 + Name *string + Size *uint64 + SystemName *string + VolumeName *string + VolumeSerialNumber *string } const wqlPhysicalDisk = "SELECT DeviceId, MediaType FROM MSFT_PhysicalDisk" @@ -106,7 +109,7 @@ type win32PhysicalDisk struct { MediaType physicalDiskMediaType } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { win32DiskDriveDescriptions, err := getDiskDrives() if err != nil { return err @@ -173,13 +176,14 @@ func (i *Info) load() error { if *logicaldisktodiskpartition.Antecedent == desiredAntecedent && *logicaldisktodiskpartition.Dependent == desiredDependent { // Appending Partition p := &Partition{ - Name: strings.TrimSpace(*logicaldisk.Caption), + Disk: disk, + Name: strings.TrimSpace(*logicaldisk.VolumeName), Label: strings.TrimSpace(*logicaldisk.Caption), SizeBytes: *logicaldisk.Size, MountPoint: *logicaldisk.DeviceID, Type: *diskpartition.Type, IsReadOnly: toReadOnly(*diskpartition.Access), - UUID: "", + UUID: *logicaldisk.VolumeSerialNumber, } disk.Partitions = append(disk.Partitions, p) break diff --git a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis.go b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis.go index a7667bbc2..bb6b6c1c4 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis.go +++ b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis.go @@ -7,9 +7,8 @@ package chassis import ( - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/util" ) @@ -56,7 +55,6 @@ var ( // Info defines chassis release information type Info struct { - ctx *context.Context AssetTag string `json:"asset_tag"` SerialNumber string `json:"serial_number"` Type string `json:"type"` @@ -89,10 +87,10 @@ func (i *Info) String() string { // New returns a pointer to a Info struct containing information // about the host's chassis -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -107,11 +105,11 @@ type chassisPrinter struct { // YAMLString returns a string with the chassis information formatted as YAML // under a top-level "dmi:" key func (info *Info) YAMLString() string { - return marshal.SafeYAML(info.ctx, chassisPrinter{info}) + return marshal.SafeYAML(chassisPrinter{info}) } // JSONString returns a string with the chassis information formatted as JSON // under a top-level "chassis:" key func (info *Info) JSONString(indent bool) string { - return marshal.SafeJSON(info.ctx, chassisPrinter{info}, indent) + return marshal.SafeJSON(chassisPrinter{info}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_linux.go b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_linux.go index 00f64de6e..408af4137 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_linux.go @@ -6,21 +6,23 @@ package chassis import ( + "context" + "github.com/jaypipes/ghw/pkg/linuxdmi" "github.com/jaypipes/ghw/pkg/util" ) -func (i *Info) load() error { - i.AssetTag = linuxdmi.Item(i.ctx, "chassis_asset_tag") - i.SerialNumber = linuxdmi.Item(i.ctx, "chassis_serial") - i.Type = linuxdmi.Item(i.ctx, "chassis_type") +func (i *Info) load(ctx context.Context) error { + i.AssetTag = linuxdmi.Item(ctx, "chassis_asset_tag") + i.SerialNumber = linuxdmi.Item(ctx, "chassis_serial") + i.Type = linuxdmi.Item(ctx, "chassis_type") typeDesc, found := chassisTypeDescriptions[i.Type] if !found { typeDesc = util.UNKNOWN } i.TypeDescription = typeDesc - i.Vendor = linuxdmi.Item(i.ctx, "chassis_vendor") - i.Version = linuxdmi.Item(i.ctx, "chassis_version") + i.Vendor = linuxdmi.Item(ctx, "chassis_vendor") + i.Version = linuxdmi.Item(ctx, "chassis_version") return nil } diff --git a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_stub.go b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_stub.go index 0e3fd94b6..6945c2713 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_stub.go @@ -9,11 +9,12 @@ package chassis import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("chassisFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_windows.go b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_windows.go index 088cbed3c..24db7efab 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/chassis/chassis_windows.go @@ -6,7 +6,9 @@ package chassis import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" "github.com/jaypipes/ghw/pkg/util" ) @@ -25,7 +27,7 @@ type win32Chassis struct { Version *string } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting data from WMI var win32ChassisDescriptions []win32Chassis if err := wmi.Query(wqlChassis, &win32ChassisDescriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/context/context.go b/vendor/github.com/jaypipes/ghw/pkg/context/context.go deleted file mode 100644 index fb8de528c..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/context/context.go +++ /dev/null @@ -1,178 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package context - -import ( - "fmt" - - "github.com/jaypipes/ghw/pkg/option" - "github.com/jaypipes/ghw/pkg/snapshot" -) - -// Context contains the merged set of configuration switches that act as an -// execution context when calling internal discovery methods -type Context struct { - Chroot string - EnableTools bool - SnapshotPath string - SnapshotRoot string - SnapshotExclusive bool - PathOverrides option.PathOverrides - snapshotUnpackedPath string - alert option.Alerter - err error -} - -// WithContext returns an option.Option that contains a pre-existing Context -// struct. This is useful for some internal code that sets up snapshots. -func WithContext(ctx *Context) *option.Option { - return &option.Option{ - Context: ctx, - } -} - -// Exists returns true if the supplied (merged) Option already contains -// a context. -// -// TODO(jaypipes): We can get rid of this when we combine the option and -// context packages, which will make it easier to detect the presence of a -// pre-setup Context. -func Exists(opt *option.Option) bool { - return opt != nil && opt.Context != nil -} - -// New returns a Context struct pointer that has had various options set on it -func New(opts ...*option.Option) *Context { - merged := option.Merge(opts...) - var ctx *Context - if merged.Context != nil { - var castOK bool - ctx, castOK = merged.Context.(*Context) - if !castOK { - panic("passed in a non-Context for the WithContext() function!") - } - return ctx - } - ctx = &Context{ - alert: option.EnvOrDefaultAlerter(), - Chroot: *merged.Chroot, - } - - if merged.Snapshot != nil { - ctx.SnapshotPath = merged.Snapshot.Path - // root is optional, so a extra check is warranted - if merged.Snapshot.Root != nil { - ctx.SnapshotRoot = *merged.Snapshot.Root - } - ctx.SnapshotExclusive = merged.Snapshot.Exclusive - } - - if merged.Alerter != nil { - ctx.alert = merged.Alerter - } - - if merged.EnableTools != nil { - ctx.EnableTools = *merged.EnableTools - } - - if merged.PathOverrides != nil { - ctx.PathOverrides = merged.PathOverrides - } - - // New is not allowed to return error - it would break the established API. - // so the only way out is to actually do the checks here and record the error, - // and return it later, at the earliest possible occasion, in Setup() - if ctx.SnapshotPath != "" && ctx.Chroot != option.DefaultChroot { - // The env/client code supplied a value, but we are will overwrite it when unpacking shapshots! - ctx.err = fmt.Errorf("Conflicting options: chroot %q and snapshot path %q", ctx.Chroot, ctx.SnapshotPath) - } - return ctx -} - -// FromEnv returns a Context that has been populated from the environs or -// default options values -func FromEnv() *Context { - chrootVal := option.EnvOrDefaultChroot() - enableTools := option.EnvOrDefaultTools() - snapPathVal := option.EnvOrDefaultSnapshotPath() - snapRootVal := option.EnvOrDefaultSnapshotRoot() - snapExclusiveVal := option.EnvOrDefaultSnapshotExclusive() - return &Context{ - Chroot: chrootVal, - EnableTools: enableTools, - SnapshotPath: snapPathVal, - SnapshotRoot: snapRootVal, - SnapshotExclusive: snapExclusiveVal, - } -} - -// Do wraps a Setup/Teardown pair around the given function -func (ctx *Context) Do(fn func() error) error { - err := ctx.Setup() - if err != nil { - return err - } - defer func() { - err := ctx.Teardown() - if err != nil { - ctx.Warn("teardown error: %v", err) - } - }() - return fn() -} - -// Setup prepares the extra optional data a Context may use. -// `Context`s are ready to use once returned by `New`. Optional features, -// like snapshot unpacking, may require extra steps. Run `Setup` to perform them. -// You should call `Setup` just once. It is safe to call `Setup` if you don't make -// use of optional extra features - `Setup` will do nothing. -func (ctx *Context) Setup() error { - if ctx.err != nil { - return ctx.err - } - if ctx.SnapshotPath == "" { - // nothing to do! - return nil - } - - var err error - root := ctx.SnapshotRoot - if root == "" { - root, err = snapshot.Unpack(ctx.SnapshotPath) - if err == nil { - ctx.snapshotUnpackedPath = root - } - } else { - var flags uint - if ctx.SnapshotExclusive { - flags |= snapshot.OwnTargetDirectory - } - _, err = snapshot.UnpackInto(ctx.SnapshotPath, root, flags) - } - if err != nil { - return err - } - - ctx.Chroot = root - return nil -} - -// Teardown releases any resource acquired by Setup. -// You should always call `Teardown` if you called `Setup` to free any resources -// acquired by `Setup`. Check `Do` for more automated management. -func (ctx *Context) Teardown() error { - if ctx.snapshotUnpackedPath == "" { - // if the client code provided the unpack directory, - // then it is also in charge of the cleanup. - return nil - } - return snapshot.Cleanup(ctx.snapshotUnpackedPath) -} - -func (ctx *Context) Warn(msg string, args ...interface{}) { - ctx.alert.Printf("WARNING: "+msg, args...) -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu.go index 5c5e6babe..91a9b4cad 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu.go @@ -9,9 +9,8 @@ package cpu import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" ) // ProcessorCore describes a physical host processor core. A processor core is @@ -122,7 +121,6 @@ func (p *Processor) String() string { // Info describes all central processing unit (CPU) functionality on a host. // Returned by the `ghw.CPU()` function. type Info struct { - ctx *context.Context // TotalCores is the total number of physical cores the host system // contains TotalCores uint32 `json:"total_cores"` @@ -140,10 +138,10 @@ type Info struct { // New returns a pointer to an Info struct that contains information about the // CPUs on the host system -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -183,11 +181,11 @@ type cpuPrinter struct { // YAMLString returns a string with the cpu information formatted as YAML // under a top-level "cpu:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, cpuPrinter{i}) + return marshal.SafeYAML(cpuPrinter{i}) } // JSONString returns a string with the cpu information formatted as JSON // under a top-level "cpu:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, cpuPrinter{i}, indent) + return marshal.SafeJSON(cpuPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_darwin.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_darwin.go index e4353e47b..61a34b17a 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_darwin.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_darwin.go @@ -1,11 +1,13 @@ package cpu import ( + "context" "fmt" - "github.com/pkg/errors" "os/exec" "strconv" "strings" + + "github.com/pkg/errors" ) var ( @@ -13,7 +15,7 @@ var ( sysctlOutput = make(map[string]string) // store all the sysctl output ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { err := populateSysctlOutput() if err != nil { return errors.Wrap(err, "unable to populate sysctl map") diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go index f403d29d9..80abe0389 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_linux.go @@ -7,6 +7,7 @@ package cpu import ( "bufio" + "context" "errors" "fmt" "os" @@ -16,7 +17,7 @@ import ( "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/util" ) @@ -26,8 +27,8 @@ var ( onlineFile = "online" ) -func (i *Info) load() error { - i.Processors = processorsGet(i.ctx) +func (i *Info) load(ctx context.Context) error { + i.Processors = processorsGet(ctx) var totCores uint32 var totThreads uint32 for _, p := range i.Processors { @@ -41,7 +42,7 @@ func (i *Info) load() error { return nil } -func processorsGet(ctx *context.Context) []*Processor { +func processorsGet(ctx context.Context) []*Processor { paths := linuxpath.New(ctx) lps := logicalProcessorsFromProcCPUInfo(ctx) @@ -53,7 +54,7 @@ func processorsGet(ctx *context.Context) []*Processor { // processor pseudodirs are of the pattern /sys/devices/system/cpu/cpu{N} fnames, err := os.ReadDir(paths.SysDevicesSystemCPU) if err != nil { - ctx.Warn("failed to read /sys/devices/system/cpu: %s", err) + log.Warn(ctx, "failed to read /sys/devices/system/cpu: %s", err) return []*Processor{} } for _, fname := range fnames { @@ -64,7 +65,7 @@ func processorsGet(ctx *context.Context) []*Processor { lpID, err := strconv.Atoi(matches[1]) if err != nil { - ctx.Warn("failed to find numeric logical processor ID: %s", err) + log.Warn(ctx, "failed to find numeric logical processor ID: %s", err) continue } @@ -83,7 +84,7 @@ func processorsGet(ctx *context.Context) []*Processor { proc = &Processor{ID: procID} lp, ok := lps[lpID] if !ok { - ctx.Warn( + log.Warn(ctx, "failed to find attributes for logical processor %d", lpID, ) @@ -94,11 +95,16 @@ func processorsGet(ctx *context.Context) []*Processor { // lps[lpID] describes logical processor `lpID`. // Once got a more robust way of fetching the following info, // can we drop /proc/cpuinfo. + // 1. Capabilities (Hardware Features) if len(lp.Attrs["flags"]) != 0 { // x86 proc.Capabilities = strings.Split(lp.Attrs["flags"], " ") } else if len(lp.Attrs["Features"]) != 0 { // ARM64 proc.Capabilities = strings.Split(lp.Attrs["Features"], " ") + } else if len(lp.Attrs["features"]) != 0 { // s390x + proc.Capabilities = strings.Split(lp.Attrs["features"], " ") } + + // 2. Model Detection if len(lp.Attrs["model name"]) != 0 { proc.Model = lp.Attrs["model name"] } else if len(lp.Attrs["Processor"]) != 0 { // ARM @@ -109,7 +115,10 @@ func processorsGet(ctx *context.Context) []*Processor { proc.Model = lp.Attrs["Model Name"] } else if len(lp.Attrs["uarch"]) != 0 { // SiFive proc.Model = lp.Attrs["uarch"] + } else if len(lp.Attrs["machine"]) != 0 { + proc.Model = lp.Attrs["machine"] } + // 3. Vendor Detection if len(lp.Attrs["vendor_id"]) != 0 { proc.Vendor = lp.Attrs["vendor_id"] } else if len(lp.Attrs["isa"]) != 0 { // RISCV64 @@ -155,7 +164,7 @@ func processorsGet(ctx *context.Context) []*Processor { // processorIDFromLogicalProcessorID returns the processor physical package ID // for the supplied logical processor ID -func processorIDFromLogicalProcessorID(ctx *context.Context, lpID int) int { +func processorIDFromLogicalProcessorID(ctx context.Context, lpID int) int { paths := linuxpath.New(ctx) // Fetch CPU ID path := filepath.Join( @@ -168,7 +177,7 @@ func processorIDFromLogicalProcessorID(ctx *context.Context, lpID int) int { // coreIDFromLogicalProcessorID returns the core ID for the supplied logical // processor ID -func coreIDFromLogicalProcessorID(ctx *context.Context, lpID int) int { +func coreIDFromLogicalProcessorID(ctx context.Context, lpID int) int { paths := linuxpath.New(ctx) // Fetch CPU ID path := filepath.Join( @@ -179,7 +188,7 @@ func coreIDFromLogicalProcessorID(ctx *context.Context, lpID int) int { return util.SafeIntFromFile(ctx, path) } -func CoresForNode(ctx *context.Context, nodeID int) ([]*ProcessorCore, error) { +func CoresForNode(ctx context.Context, nodeID int) ([]*ProcessorCore, error) { // The /sys/devices/system/node/nodeX directory contains a subdirectory // called 'cpuX' for each logical processor assigned to the node. Each of // those subdirectories contains a topology subdirectory which has a @@ -227,7 +236,7 @@ func CoresForNode(ctx *context.Context, nodeID int) ([]*ProcessorCore, error) { cpuPath := filepath.Join(path, filename) procID, err := strconv.Atoi(filename[3:]) if err != nil { - ctx.Warn( + log.Warn(ctx, "failed to determine procID from %s. Expected integer after 3rd char.", filename, ) @@ -339,7 +348,7 @@ type logicalProcessor struct { // with blank line-separated blocks of colon-delimited attribute name/value // pairs for a specific logical processor on the host. func logicalProcessorsFromProcCPUInfo( - ctx *context.Context, + ctx context.Context, ) map[int]*logicalProcessor { paths := linuxpath.New(ctx) r, err := os.Open(paths.ProcCpuinfo) @@ -360,25 +369,41 @@ func logicalProcessorsFromProcCPUInfo( // Output of /proc/cpuinfo has a blank newline to separate logical // processors, so here we collect up all the attributes we've // collected for this logical processor block - lpIDstr, ok := lpAttrs["processor"] + // s390x identifies CPUs via "cpu number", while most other + // architectures use "processor". + idStr, ok := lpAttrs["processor"] if !ok { - ctx.Warn("expected to find 'processor' key in /proc/cpuinfo attributes") - continue + idStr, ok = lpAttrs["cpu number"] } - lpID, _ := strconv.Atoi(lpIDstr) - lp := &logicalProcessor{ - ID: lpID, - Attrs: lpAttrs, + + if ok { + id, _ := strconv.Atoi(idStr) + lps[id] = &logicalProcessor{ + ID: id, + Attrs: lpAttrs, + } + // Only reset attributes after a valid processor block is saved. + // This ensures that shared header metadata (like vendor_id on s390x) + // is carried over and available to the processor entries. + lpAttrs = map[string]string{} + } else if len(lpAttrs) > 0 { + // s390x header check: if we have 'vendor_id' but no 'processor' ID, + // it's the summary block. We don't warn and we don't reset lpAttrs + // so the vendor_id carries over to the first actual CPU block. + if _, isS390Header := lpAttrs["vendor_id"]; !isS390Header { + log.Warn(ctx, + "expected to find 'processor' or 'cpu number' key "+ + "in /proc/cpuinfo attributes") + } } - lps[lpID] = lp - // Reset the current set of processor attributes... - lpAttrs = map[string]string{} continue } - parts := strings.Split(line, ":") - key := strings.TrimSpace(parts[0]) - value := strings.TrimSpace(parts[1]) - lpAttrs[key] = value + parts := strings.SplitN(line, ":", 2) + if len(parts) >= 2 { + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + lpAttrs[key] = value + } } return lps } diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_stub.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_stub.go index 85156069a..970124c96 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_stub.go @@ -9,11 +9,12 @@ package cpu import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("cpu.Info.load not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_windows.go b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_windows.go index bd4b84699..d0851a9c4 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/cpu/cpu_windows.go @@ -9,7 +9,9 @@ package cpu import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" ) const wmqlProcessor = "SELECT Manufacturer, Name, NumberOfLogicalProcessors, NumberOfCores FROM Win32_Processor" @@ -21,7 +23,7 @@ type win32Processor struct { NumberOfCores uint32 } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting info from WMI var win32descriptions []win32Processor if err := wmi.Query(wmqlProcessor, &win32descriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu.go b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu.go index 65864c7e1..a62079120 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu.go +++ b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu.go @@ -9,9 +9,8 @@ package gpu import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/pci" "github.com/jaypipes/ghw/pkg/topology" ) @@ -49,16 +48,15 @@ func (card *GraphicsCard) String() string { } type Info struct { - ctx *context.Context GraphicsCards []*GraphicsCard `json:"cards"` } // New returns a pointer to an Info struct that contains information about the // graphics cards on the host system -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -85,11 +83,11 @@ type gpuPrinter struct { // YAMLString returns a string with the gpu information formatted as YAML // under a top-level "gpu:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, gpuPrinter{i}) + return marshal.SafeYAML(gpuPrinter{i}) } // JSONString returns a string with the gpu information formatted as JSON // under a top-level "gpu:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, gpuPrinter{i}, indent) + return marshal.SafeJSON(gpuPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_linux.go b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_linux.go index e5e341c12..4421ecc39 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_linux.go @@ -6,13 +6,16 @@ package gpu import ( + "context" + "fmt" "os" "path/filepath" "regexp" "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/pci" "github.com/jaypipes/ghw/pkg/topology" @@ -20,20 +23,16 @@ import ( ) const ( - validPCIAddress = `\b(0{0,4}:\d{2}:\d{2}.\d:?\w*)` + validPCIAddress = `\b(0{0,4}:[[:xdigit:]]{2}:[[:xdigit:]]{2}\.[[:xdigit:]]:?\w*)` ) var reValidPCIAddress = regexp.MustCompile(validPCIAddress) const ( - _WARN_NO_SYS_CLASS_DRM = ` -/sys/class/drm does not exist on this system (likely the host system is a -virtual machine or container with no graphics). Therefore, -GPUInfo.GraphicsCards will be an empty array. -` + warnNoSysClassDRM = `/sys/class/drm does not exist on this system (likely the host system is a virtual machine or container with no graphics). Therefore, GPUInfo.GraphicsCards will be an empty array.` ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // In Linux, each graphics card is listed under the /sys/class/drm // directory as a symbolic link named "cardN", where N is a zero-based // index of the card in the system. "DRM" stands for Direct Rendering @@ -60,10 +59,14 @@ func (i *Info) load() error { // we follow to gather information about the actual device from the PCI // subsystem (we query the modalias file of the PCI device's sysfs // directory using the `ghw.PCIInfo.GetDevice()` function. - paths := linuxpath.New(i.ctx) + pci, err := pci.New(ctx) + if err != nil { + return fmt.Errorf("failed to initialize PCI device database: %w", err) + } + paths := linuxpath.New(ctx) links, err := os.ReadDir(paths.SysClassDRM) if err != nil { - i.ctx.Warn(_WARN_NO_SYS_CLASS_DRM) + log.Warn(ctx, warnNoSysClassDRM) return nil } cards := make([]*GraphicsCard, 0) @@ -109,20 +112,15 @@ func (i *Info) load() error { } cards = append(cards, card) } - gpuFillNUMANodes(i.ctx, cards) - gpuFillPCIDevice(i.ctx, cards) + gpuFillNUMANodes(ctx, cards) + gpuFillPCIDevice(pci, cards) i.GraphicsCards = cards return nil } // Loops through each GraphicsCard struct and attempts to fill the DeviceInfo // attribute with PCI device information -func gpuFillPCIDevice(ctx *context.Context, cards []*GraphicsCard) { - pci, err := pci.New(context.WithContext(ctx)) - if err != nil { - ctx.Warn("failed to PCI device database: %s", err) - return - } +func gpuFillPCIDevice(pci *pci.Info, cards []*GraphicsCard) { for _, card := range cards { if card.DeviceInfo == nil { card.DeviceInfo = pci.GetDevice(card.Address) @@ -133,16 +131,22 @@ func gpuFillPCIDevice(ctx *context.Context, cards []*GraphicsCard) { // Loops through each GraphicsCard struct and find which NUMA node the card is // affined to, setting the GraphicsCard.Node field accordingly. If the host // system is not a NUMA system, the Node field will be set to nil. -func gpuFillNUMANodes(ctx *context.Context, cards []*GraphicsCard) { +func gpuFillNUMANodes(ctx context.Context, cards []*GraphicsCard) { paths := linuxpath.New(ctx) - topo, err := topology.New(context.WithContext(ctx)) + // Skip topology detection if requested to reduce memory consumption + if !config.TopologyEnabled(ctx) { + for _, card := range cards { + card.Node = nil + } + return + } + + topo, err := topology.New(ctx) if err != nil { // Problem getting topology information so just set the graphics card's // node to nil for _, card := range cards { - if topo.Architecture != topology.ArchitectureNUMA { - card.Node = nil - } + card.Node = nil } return } diff --git a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_stub.go b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_stub.go index 48991ec8e..01d223dd8 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_stub.go @@ -9,11 +9,12 @@ package gpu import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("gpuFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_windows.go b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_windows.go index 70e19918c..7a58432cd 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/gpu/gpu_windows.go @@ -6,10 +6,11 @@ package gpu import ( + "context" "strings" - "github.com/StackExchange/wmi" "github.com/jaypipes/pcidb" + "github.com/yusufpapurcu/wmi" "github.com/jaypipes/ghw/pkg/pci" "github.com/jaypipes/ghw/pkg/util" @@ -46,7 +47,7 @@ type win32PnPEntity struct { PNPDeviceID string } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting data from WMI var win32VideoControllerDescriptions []win32VideoController if err := wmi.Query(wqlVideoController, &win32VideoControllerDescriptions); err != nil { @@ -56,7 +57,7 @@ func (i *Info) load() error { // Building dynamic WHERE clause with addresses to create a single query collecting all desired data queryAddresses := []string{} for _, description := range win32VideoControllerDescriptions { - var queryAddres = strings.Replace(description.PNPDeviceID, "\\", `\\`, -1) + var queryAddres = strings.ReplaceAll(description.PNPDeviceID, "\\", `\\`) queryAddresses = append(queryAddresses, "PNPDeviceID='"+queryAddres+"'") } whereClause := strings.Join(queryAddresses[:], " OR ") @@ -85,7 +86,7 @@ func (i *Info) load() error { func GetDevice(id string, entities []win32PnPEntity) *pci.Device { // Backslashing PnP address ID as requested by JSON and VMI query: https://docs.microsoft.com/en-us/windows/win32/wmisdk/where-clause - var queryAddress = strings.Replace(id, "\\", `\\`, -1) + var queryAddress = strings.ReplaceAll(id, "\\", `\\`) // Preparing default structure var device = &pci.Device{ Address: queryAddress, diff --git a/vendor/github.com/jaypipes/ghw/pkg/linuxdmi/dmi_linux.go b/vendor/github.com/jaypipes/ghw/pkg/linuxdmi/dmi_linux.go index 8e6d8302d..6b373a7a2 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/linuxdmi/dmi_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/linuxdmi/dmi_linux.go @@ -6,22 +6,24 @@ package linuxdmi import ( + "context" "os" "path/filepath" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/util" ) -func Item(ctx *context.Context, value string) string { +func Item(ctx context.Context, value string) string { paths := linuxpath.New(ctx) path := filepath.Join(paths.SysClassDMI, "id", value) + log.Debug(ctx, "reading from %q", path) b, err := os.ReadFile(path) if err != nil { - ctx.Warn("Unable to read %s: %s\n", value, err) + log.Warn(ctx, "Unable to read %s: %s\n", value, err) return util.UNKNOWN } diff --git a/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go b/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go index bbe81b64e..c08869158 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/linuxpath/path_linux.go @@ -6,10 +6,11 @@ package linuxpath import ( + "context" "fmt" "path/filepath" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" ) // PathRoots holds the roots of all the filesystem subtrees @@ -35,27 +36,29 @@ func DefaultPathRoots() PathRoots { // PathRootsFromContext initialize PathRoots from the given Context, // allowing overrides of the canonical default paths. -func PathRootsFromContext(ctx *context.Context) PathRoots { +func PathRootsFromContext(ctx context.Context) PathRoots { roots := DefaultPathRoots() - if pathEtc, ok := ctx.PathOverrides["/etc"]; ok { + overrides := config.PathOverrides(ctx) + if pathEtc, ok := overrides["/etc"]; ok { roots.Etc = pathEtc } - if pathProc, ok := ctx.PathOverrides["/proc"]; ok { + if pathProc, ok := overrides["/proc"]; ok { roots.Proc = pathProc } - if pathRun, ok := ctx.PathOverrides["/run"]; ok { + if pathRun, ok := overrides["/run"]; ok { roots.Run = pathRun } - if pathSys, ok := ctx.PathOverrides["/sys"]; ok { + if pathSys, ok := overrides["/sys"]; ok { roots.Sys = pathSys } - if pathVar, ok := ctx.PathOverrides["/var"]; ok { + if pathVar, ok := overrides["/var"]; ok { roots.Var = pathVar } return roots } type Paths struct { + SysRoot string VarLog string ProcMeminfo string ProcCpuinfo string @@ -66,6 +69,7 @@ type Paths struct { SysDevicesSystemMemory string SysDevicesSystemCPU string SysBusPciDevices string + SysBusUsbDevices string SysClassDRM string SysClassDMI string SysClassNet string @@ -74,23 +78,26 @@ type Paths struct { // New returns a new Paths struct containing filepath fields relative to the // supplied Context -func New(ctx *context.Context) *Paths { +func New(ctx context.Context) *Paths { roots := PathRootsFromContext(ctx) + chroot := config.Chroot(ctx) return &Paths{ - VarLog: filepath.Join(ctx.Chroot, roots.Var, "log"), - ProcMeminfo: filepath.Join(ctx.Chroot, roots.Proc, "meminfo"), - ProcCpuinfo: filepath.Join(ctx.Chroot, roots.Proc, "cpuinfo"), - ProcMounts: filepath.Join(ctx.Chroot, roots.Proc, "self", "mounts"), - SysKernelMMHugepages: filepath.Join(ctx.Chroot, roots.Sys, "kernel", "mm", "hugepages"), - SysBlock: filepath.Join(ctx.Chroot, roots.Sys, "block"), - SysDevicesSystemNode: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "node"), - SysDevicesSystemMemory: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "memory"), - SysDevicesSystemCPU: filepath.Join(ctx.Chroot, roots.Sys, "devices", "system", "cpu"), - SysBusPciDevices: filepath.Join(ctx.Chroot, roots.Sys, "bus", "pci", "devices"), - SysClassDRM: filepath.Join(ctx.Chroot, roots.Sys, "class", "drm"), - SysClassDMI: filepath.Join(ctx.Chroot, roots.Sys, "class", "dmi"), - SysClassNet: filepath.Join(ctx.Chroot, roots.Sys, "class", "net"), - RunUdevData: filepath.Join(ctx.Chroot, roots.Run, "udev", "data"), + SysRoot: filepath.Join(chroot, roots.Sys), + VarLog: filepath.Join(chroot, roots.Var, "log"), + ProcMeminfo: filepath.Join(chroot, roots.Proc, "meminfo"), + ProcCpuinfo: filepath.Join(chroot, roots.Proc, "cpuinfo"), + ProcMounts: filepath.Join(chroot, roots.Proc, "self", "mounts"), + SysKernelMMHugepages: filepath.Join(chroot, roots.Sys, "kernel", "mm", "hugepages"), + SysBlock: filepath.Join(chroot, roots.Sys, "block"), + SysDevicesSystemNode: filepath.Join(chroot, roots.Sys, "devices", "system", "node"), + SysDevicesSystemMemory: filepath.Join(chroot, roots.Sys, "devices", "system", "memory"), + SysDevicesSystemCPU: filepath.Join(chroot, roots.Sys, "devices", "system", "cpu"), + SysBusPciDevices: filepath.Join(chroot, roots.Sys, "bus", "pci", "devices"), + SysBusUsbDevices: filepath.Join(chroot, roots.Sys, "bus", "usb", "devices"), + SysClassDRM: filepath.Join(chroot, roots.Sys, "class", "drm"), + SysClassDMI: filepath.Join(chroot, roots.Sys, "class", "dmi"), + SysClassNet: filepath.Join(chroot, roots.Sys, "class", "net"), + RunUdevData: filepath.Join(chroot, roots.Run, "udev", "data"), } } diff --git a/vendor/github.com/jaypipes/ghw/pkg/marshal/marshal.go b/vendor/github.com/jaypipes/ghw/pkg/marshal/marshal.go index e442d6aff..c8567ce74 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/marshal/marshal.go +++ b/vendor/github.com/jaypipes/ghw/pkg/marshal/marshal.go @@ -9,27 +9,23 @@ package marshal import ( "encoding/json" - "github.com/jaypipes/ghw/pkg/context" yaml "gopkg.in/yaml.v3" ) // SafeYAML returns a string after marshalling the supplied parameter into YAML. -func SafeYAML(ctx *context.Context, p interface{}) string { +func SafeYAML(p interface{}) string { b, err := json.Marshal(p) if err != nil { - ctx.Warn("error marshalling JSON: %s", err) return "" } var jsonObj interface{} if err := yaml.Unmarshal(b, &jsonObj); err != nil { - ctx.Warn("error converting JSON to YAML: %s", err) return "" } yb, err := yaml.Marshal(jsonObj) if err != nil { - ctx.Warn("error marshalling YAML: %s", err) return "" } @@ -39,7 +35,7 @@ func SafeYAML(ctx *context.Context, p interface{}) string { // SafeJSON returns a string after marshalling the supplied parameter into // JSON. Accepts an optional argument to trigger pretty/indented formatting of // the JSON string. -func SafeJSON(ctx *context.Context, p interface{}, indent bool) string { +func SafeJSON(p interface{}, indent bool) string { var b []byte var err error if !indent { @@ -48,7 +44,6 @@ func SafeJSON(ctx *context.Context, p interface{}, indent bool) string { b, err = json.MarshalIndent(&p, "", " ") } if err != nil { - ctx.Warn("error marshalling JSON: %s", err) return "" } return string(b) diff --git a/vendor/github.com/jaypipes/ghw/pkg/memory/memory.go b/vendor/github.com/jaypipes/ghw/pkg/memory/memory.go index f58ba8b91..e043adaed 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/memory/memory.go +++ b/vendor/github.com/jaypipes/ghw/pkg/memory/memory.go @@ -10,9 +10,8 @@ import ( "fmt" "math" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/unitutil" "github.com/jaypipes/ghw/pkg/util" ) @@ -78,15 +77,14 @@ func (a *Area) String() string { // Info contains information about the memory on a host system. type Info struct { - ctx *context.Context Area } // New returns an Info struct that describes the memory on a host system. -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -106,11 +104,11 @@ type memoryPrinter struct { // YAMLString returns a string with the memory information formatted as YAML // under a top-level "memory:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, memoryPrinter{i}) + return marshal.SafeYAML(memoryPrinter{i}) } // JSONString returns a string with the memory information formatted as JSON // under a top-level "memory:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, memoryPrinter{i}, indent) + return marshal.SafeJSON(memoryPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_cache_linux.go b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_cache_linux.go index 12258ea4e..93df0d17e 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_cache_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_cache_linux.go @@ -6,6 +6,7 @@ package memory import ( + "context" "errors" "fmt" "os" @@ -14,12 +15,12 @@ import ( "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/unitutil" ) -func CachesForNode(ctx *context.Context, nodeID int) ([]*Cache, error) { +func CachesForNode(ctx context.Context, nodeID int) ([]*Cache, error) { // The /sys/devices/node/nodeX directory contains a subdirectory called // 'cpuX' for each logical processor assigned to the node. Each of those // subdirectories containers a 'cache' subdirectory which contains a number @@ -81,8 +82,20 @@ func CachesForNode(ctx *context.Context, nodeID int) ([]*Cache, error) { // unique combination of level, type and processor map level := memoryCacheLevel(ctx, paths, nodeID, lpID, cacheIndex) cacheType := memoryCacheType(ctx, paths, nodeID, lpID, cacheIndex) - sharedCpuMap := memoryCacheSharedCPUMap(ctx, paths, nodeID, lpID, cacheIndex) - cacheKey := fmt.Sprintf("%d-%d-%s", level, cacheType, sharedCpuMap) + cacheID := memoryCacheID(ctx, paths, nodeID, lpID, cacheIndex) + + // Generate cache key for deduplication. + // Use cache ID if available (modern kernels), otherwise fall back + // to shared_cpu_map for older kernels. This ensures that caches + // shared across NUMA nodes (e.g., L3 in Sub-NUMA Clustering) are + // correctly merged into a single cache object. + var cacheKey string + if cacheID != -1 { + cacheKey = fmt.Sprintf("%d-%d-%d", level, cacheType, cacheID) + } else { + sharedCpuMap := memoryCacheSharedCPUMap(ctx, paths, nodeID, lpID, cacheIndex) + cacheKey = fmt.Sprintf("%d-%d-%s", level, cacheType, sharedCpuMap) + } cache, exists := caches[cacheKey] if !exists { @@ -114,53 +127,95 @@ func CachesForNode(ctx *context.Context, nodeID int) ([]*Cache, error) { return cacheVals, nil } -func memoryCacheLevel(ctx *context.Context, paths *linuxpath.Paths, nodeID int, lpID int, cacheIndex int) int { +func memoryCacheLevel( + ctx context.Context, + paths *linuxpath.Paths, + nodeID int, + lpID int, + cacheIndex int, +) int { levelPath := filepath.Join( paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex), "level", ) levelContents, err := os.ReadFile(levelPath) if err != nil { - ctx.Warn("%s", err) + log.Warn(ctx, "%s", err) return -1 } // levelContents is now a []byte with the last byte being a newline // character. Trim that off and convert the contents to an integer. level, err := strconv.Atoi(string(levelContents[:len(levelContents)-1])) if err != nil { - ctx.Warn("Unable to parse int from %s", levelContents) + log.Warn(ctx, "Unable to parse int from %s", levelContents) return -1 } return level } -func memoryCacheSize(ctx *context.Context, paths *linuxpath.Paths, nodeID int, lpID int, cacheIndex int) int { +func memoryCacheID( + ctx context.Context, + paths *linuxpath.Paths, + nodeID int, + lpID int, + cacheIndex int, +) int { + idPath := filepath.Join( + paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex), + "id", + ) + idContents, err := os.ReadFile(idPath) + if err != nil { + // The id file may not exist in early kernel versions, so we don't warn + return -1 + } + id, err := strconv.Atoi(string(idContents[:len(idContents)-1])) + if err != nil { + log.Warn(ctx, "Unable to parse int from %s", idContents) + return -1 + } + return id +} + +func memoryCacheSize( + ctx context.Context, + paths *linuxpath.Paths, + nodeID int, + lpID int, + cacheIndex int, +) int { sizePath := filepath.Join( paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex), "size", ) sizeContents, err := os.ReadFile(sizePath) if err != nil { - ctx.Warn("%s", err) + log.Warn(ctx, "%s", err) return -1 } // size comes as XK\n, so we trim off the K and the newline. size, err := strconv.Atoi(string(sizeContents[:len(sizeContents)-2])) if err != nil { - ctx.Warn("Unable to parse int from %s", sizeContents) + log.Warn(ctx, "Unable to parse int from %s", sizeContents) return -1 } return size } -func memoryCacheType(ctx *context.Context, paths *linuxpath.Paths, nodeID int, lpID int, cacheIndex int) CacheType { +func memoryCacheType( + ctx context.Context, + paths *linuxpath.Paths, + nodeID int, + lpID int, + cacheIndex int, +) CacheType { typePath := filepath.Join( paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex), "type", ) cacheTypeContents, err := os.ReadFile(typePath) if err != nil { - ctx.Warn("%s", err) + log.Warn(ctx, "%s", err) return CacheTypeUnified } switch string(cacheTypeContents[:len(cacheTypeContents)-1]) { @@ -173,14 +228,20 @@ func memoryCacheType(ctx *context.Context, paths *linuxpath.Paths, nodeID int, l } } -func memoryCacheSharedCPUMap(ctx *context.Context, paths *linuxpath.Paths, nodeID int, lpID int, cacheIndex int) string { +func memoryCacheSharedCPUMap( + ctx context.Context, + paths *linuxpath.Paths, + nodeID int, + lpID int, + cacheIndex int, +) string { scpuPath := filepath.Join( paths.NodeCPUCacheIndex(nodeID, lpID, cacheIndex), "shared_cpu_map", ) sharedCpuMap, err := os.ReadFile(scpuPath) if err != nil { - ctx.Warn("%s", err) + log.Warn(ctx, "%s", err) return "" } return string(sharedCpuMap[:len(sharedCpuMap)-1]) diff --git a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_linux.go b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_linux.go index 53acfd5c7..4e6f21186 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_linux.go @@ -8,6 +8,7 @@ package memory import ( "bufio" "compress/gzip" + "context" "fmt" "io" "os" @@ -17,21 +18,14 @@ import ( "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/unitutil" "github.com/jaypipes/ghw/pkg/util" ) const ( - warnCannotDeterminePhysicalMemory = ` -Could not determine total physical bytes of memory. This may -be due to the host being a virtual machine or container with no -/var/log/syslog file or /sys/devices/system/memory directory, or -the current user may not have necessary privileges to read the syslog. -We are falling back to setting the total physical amount of memory to -the total usable amount of memory -` + warnCannotDeterminePhysicalMemory = `Could not determine total physical bytes of memory. This may be due to the host being a virtual machine or container with no /var/log/syslog file or /sys/devices/system/memory directory, or the current user may not have necessary privileges to read the syslog. We are falling back to setting the total physical amount of memory to the total usable amount of memory` ) var ( @@ -44,8 +38,8 @@ var ( regexMemoryBlockDirname = regexp.MustCompile(`memory\d+$`) ) -func (i *Info) load() error { - paths := linuxpath.New(i.ctx) +func (i *Info) load(ctx context.Context) error { + paths := linuxpath.New(ctx) tub := memTotalUsableBytes(paths) if tub < 1 { return fmt.Errorf("Could not determine total usable bytes of memory") @@ -54,7 +48,7 @@ func (i *Info) load() error { tpb := memTotalPhysicalBytes(paths) i.TotalPhysicalBytes = tpb if tpb < 1 { - i.ctx.Warn(warnCannotDeterminePhysicalMemory) + log.Warn(ctx, warnCannotDeterminePhysicalMemory) i.TotalPhysicalBytes = tub } i.SupportedPageSizes, _ = memorySupportedPageSizes(paths.SysKernelMMHugepages) @@ -72,8 +66,7 @@ func (i *Info) load() error { return nil } -func AreaForNode(ctx *context.Context, nodeID int) (*Area, error) { - paths := linuxpath.New(ctx) +func AreaForNode(paths *linuxpath.Paths, nodeID int) (*Area, error) { path := filepath.Join( paths.SysDevicesSystemNode, fmt.Sprintf("node%d", nodeID), @@ -242,7 +235,7 @@ func memTotalPhysicalBytesFromSyslog(paths *linuxpath.Paths) int64 { for _, file := range logFiles { if strings.HasPrefix(file.Name(), "syslog") { fullPath := filepath.Join(logDir, file.Name()) - unzip := strings.HasSuffix(file.Name(), ".gz") + unzip := filepath.Ext(file.Name()) == ".gz" var r io.ReadCloser r, err = os.Open(fullPath) if err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_stub.go b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_stub.go index 6ce99e00d..a7e69dd27 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_stub.go @@ -9,11 +9,12 @@ package memory import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("mem.Info.load not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_windows.go b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_windows.go index c3a3945ca..9ada287df 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/memory/memory_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/memory/memory_windows.go @@ -7,7 +7,9 @@ package memory import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" "github.com/jaypipes/ghw/pkg/unitutil" ) @@ -37,7 +39,7 @@ type win32PhysicalMemory struct { TotalWidth *uint16 } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting info from WMI var win32OSDescriptions []win32OperatingSystem if err := wmi.Query(wqlOperatingSystem, &win32OSDescriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/net/net.go b/vendor/github.com/jaypipes/ghw/pkg/net/net.go index e26dab702..21b7e6212 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/net/net.go +++ b/vendor/github.com/jaypipes/ghw/pkg/net/net.go @@ -9,9 +9,8 @@ package net import ( "fmt" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" ) // NICCapability is a feature/capability of a Network Interface Controller @@ -95,7 +94,6 @@ func (n *NIC) String() string { // Info describes all network interface controllers (NICs) in the host system. type Info struct { - ctx *context.Context // NICs is a slice of pointers to `NIC` structs describing the network // interface controllers (NICs) on the host system. NICs []*NIC `json:"nics"` @@ -103,10 +101,10 @@ type Info struct { // New returns a pointer to an Info struct that contains information about the // network interface controllers (NICs) on the host system -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -130,11 +128,11 @@ type netPrinter struct { // YAMLString returns a string with the net information formatted as YAML // under a top-level "net:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, netPrinter{i}) + return marshal.SafeYAML(netPrinter{i}) } // JSONString returns a string with the net information formatted as JSON // under a top-level "net:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, netPrinter{i}, indent) + return marshal.SafeJSON(netPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/net/net_linux.go b/vendor/github.com/jaypipes/ghw/pkg/net/net_linux.go index d7d7e8caf..86542b936 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/net/net_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/net/net_linux.go @@ -8,13 +8,15 @@ package net import ( "bufio" "bytes" + "context" "fmt" "os" "os/exec" "path/filepath" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" "github.com/jaypipes/ghw/pkg/util" ) @@ -23,12 +25,12 @@ const ( warnEthtoolNotInstalled = `ethtool not installed. Cannot grab NIC capabilities` ) -func (i *Info) load() error { - i.NICs = nics(i.ctx) +func (i *Info) load(ctx context.Context) error { + i.NICs = nics(ctx) return nil } -func nics(ctx *context.Context) []*NIC { +func nics(ctx context.Context) []*NIC { nics := make([]*NIC, 0) paths := linuxpath.New(ctx) @@ -37,18 +39,18 @@ func nics(ctx *context.Context) []*NIC { return nics } - etAvailable := ctx.EnableTools + etAvailable := config.ToolsEnabled(ctx) if etAvailable { if etInstalled := ethtoolInstalled(); !etInstalled { - ctx.Warn(warnEthtoolNotInstalled) + log.Warn(ctx, warnEthtoolNotInstalled) etAvailable = false } } for _, file := range files { filename := file.Name() - // Ignore loopback... - if filename == "lo" { + // Ignore loopback and bonding_masters + if filename == "lo" || filename == "bonding_masters" { continue } @@ -108,7 +110,7 @@ func ethtoolInstalled() bool { return err == nil } -func (n *NIC) netDeviceParseEthtool(ctx *context.Context, dev string) { +func (n *NIC) netDeviceParseEthtool(ctx context.Context, dev string) { var out bytes.Buffer path, _ := exec.LookPath("ethtool") @@ -133,7 +135,7 @@ func (n *NIC) netDeviceParseEthtool(ctx *context.Context, dev string) { n.AdvertisedFECModes = m["Advertised FEC modes"] } else { msg := fmt.Sprintf("could not grab NIC link info for %s: %s", dev, err) - ctx.Warn(msg) + log.Warn(ctx, msg) } // Get all other capabilities from "ethtool -k" @@ -171,9 +173,8 @@ func (n *NIC) netDeviceParseEthtool(ctx *context.Context, dev string) { } else { msg := fmt.Sprintf("could not grab NIC capabilities for %s: %s", dev, err) - ctx.Warn(msg) + log.Warn(ctx, msg) } - } // netParseEthtoolFeature parses a line from the ethtool -k output and returns diff --git a/vendor/github.com/jaypipes/ghw/pkg/net/net_stub.go b/vendor/github.com/jaypipes/ghw/pkg/net/net_stub.go index c8dfa090d..fc6a44718 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/net/net_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/net/net_stub.go @@ -9,11 +9,12 @@ package net import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("netFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/net/net_windows.go b/vendor/github.com/jaypipes/ghw/pkg/net/net_windows.go index 7efc0946c..5d02441bd 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/net/net_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/net/net_windows.go @@ -6,9 +6,10 @@ package net import ( + "context" "strings" - "github.com/StackExchange/wmi" + "github.com/yusufpapurcu/wmi" ) const wqlNetworkAdapter = "SELECT Description, DeviceID, Index, InterfaceIndex, MACAddress, Manufacturer, Name, NetConnectionID, ProductName, ServiceName, PhysicalAdapter FROM Win32_NetworkAdapter" @@ -27,7 +28,7 @@ type win32NetworkAdapter struct { PhysicalAdapter *bool } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting info from WMI var win32NetDescriptions []win32NetworkAdapter if err := wmi.Query(wqlNetworkAdapter, &win32NetDescriptions); err != nil { diff --git a/vendor/github.com/jaypipes/ghw/pkg/option/option.go b/vendor/github.com/jaypipes/ghw/pkg/option/option.go index 7ce14016d..59a310d37 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/option/option.go +++ b/vendor/github.com/jaypipes/ghw/pkg/option/option.go @@ -4,12 +4,17 @@ // See the COPYING file in the root project directory for full text. // +// NOTE(jaypipes): This entire package is deprecated and will be removed in the +// 1.0 release of ghw. Please use the aliased definitions of WithXXX functions +// in the main `ghw` package. package option import ( "io" "log" "os" + + "github.com/jaypipes/pcidb" ) const ( @@ -62,197 +67,125 @@ func EnvOrDefaultChroot() string { return DefaultChroot } -// EnvOrDefaultSnapshotPath returns the value of the GHW_SNAPSHOT_PATH environs variable -// or the default value of "" (disable snapshot consumption) if not set -func EnvOrDefaultSnapshotPath() string { - if val, exists := os.LookupEnv(envKeySnapshotPath); exists { - return val - } - return "" // default is no snapshot -} - -// EnvOrDefaultSnapshotRoot returns the value of the the GHW_SNAPSHOT_ROOT environs variable -// or the default value of "" (self-manage the snapshot unpack directory, if relevant) if not set -func EnvOrDefaultSnapshotRoot() string { - if val, exists := os.LookupEnv(envKeySnapshotRoot); exists { - return val - } - return "" // default is to self-manage the snapshot directory -} - -// EnvOrDefaultSnapshotExclusive returns the value of the GHW_SNAPSHOT_EXCLUSIVE environs variable -// or the default value of false if not set -func EnvOrDefaultSnapshotExclusive() bool { - if _, exists := os.LookupEnv(envKeySnapshotExclusive); exists { - return true - } - return false -} - -// EnvOrDefaultSnapshotPreserve returns the value of the GHW_SNAPSHOT_PRESERVE environs variable -// or the default value of false if not set -func EnvOrDefaultSnapshotPreserve() bool { - if _, exists := os.LookupEnv(envKeySnapshotPreserve); exists { - return true - } - return false -} - -// EnvOrDefaultTools return true if ghw should use external tools to augment the data collected -// from sysfs. Most users want to do this most of time, so this is enabled by default. -// Users consuming snapshots may want to opt out, thus they can set the GHW_DISABLE_TOOLS -// environs variable to any value to make ghw skip calling external tools even if they are available. -func EnvOrDefaultTools() bool { +// EnvOrDefaultDisableTools return true if ghw should use external tools to +// augment the data collected from sysfs. Most users want to do this most of +// time, so this is enabled by default. Users consuming snapshots may want to +// opt out, thus they can set the GHW_DISABLE_TOOLS environs variable to any +// value to make ghw skip calling external tools even if they are available. +func EnvOrDefaultDisableTools() bool { if _, exists := os.LookupEnv(envKeyDisableTools); exists { return false } return true } -// Option is used to represent optionally-configured settings. Each field is a +// Options is used to represent optionally-configured settings. Each field is a // pointer to some concrete value so that we can tell when something has been // set or left unset. -type Option struct { +type Options struct { // To facilitate querying of sysfs filesystems that are bind-mounted to a - // non-default root mountpoint, we allow users to set the GHW_CHROOT environ - // variable to an alternate mountpoint. For instance, assume that the user of - // ghw is a Golang binary being executed from an application container that has - // certain host filesystems bind-mounted into the container at /host. The user - // would ensure the GHW_CHROOT environ variable is set to "/host" and ghw will - // build its paths from that location instead of / - Chroot *string - - // Snapshot contains options for handling ghw snapshots - Snapshot *SnapshotOptions + // non-default root mountpoint, we allow users to set the GHW_CHROOT + // environ variable to an alternate mountpoint. For instance, assume that + // the user of ghw is a Golang binary being executed from an application + // container that has certain host filesystems bind-mounted into the + // container at /host. The user would ensure the GHW_CHROOT environ + // variable is set to "/host" and ghw will build its paths from that + // location instead of / + Chroot string // Alerter contains the target for ghw warnings Alerter Alerter - // EnableTools optionally request ghw to not call any external program to learn + // DisableTools optionally request ghw to not call any external program to learn // about the hardware. The default is to use such tools if available. - EnableTools *bool + DisableTools bool - // PathOverrides optionally allows to override the default paths ghw uses internally - // to learn about the system resources. + // PathOverrides optionally allows to override the default paths ghw uses + // internally to learn about the system resources. PathOverrides PathOverrides - // Context may contain a pointer to a `Context` struct that is constructed - // during a call to the `context.WithContext` function. Only used internally. - // This is an interface to get around recursive package import issues. - Context interface{} + // PCIDB allows users to provide a custom instance of the PCI database + // (pcidb.PCIDB) to be used by ghw. This can be useful for testing, + // supplying a preloaded database, or providing an instance created with + // custom pcidb.WithOption settings, instead of letting ghw load the PCI + // database automatically. + PCIDB *pcidb.PCIDB } -// SnapshotOptions contains options for handling of ghw snapshots -type SnapshotOptions struct { - // Path allows users to specify a snapshot (captured using ghw-snapshot) to be - // automatically consumed. Users need to supply the path of the snapshot, and - // ghw will take care of unpacking it on a temporary directory. - // Set the environment variable "GHW_SNAPSHOT_PRESERVE" to make ghw skip the cleanup - // stage and keep the unpacked snapshot in the temporary directory. - Path string - // Root is the directory on which the snapshot must be unpacked. This allows - // the users to manage their snapshot directory instead of ghw doing that on - // their behalf. Relevant only if SnapshotPath is given. - Root *string - // Exclusive tells ghw if the given directory should be considered of exclusive - // usage of ghw or not If the user provides a Root. If the flag is set, ghw will - // unpack the snapshot in the given SnapshotRoot iff the directory is empty; otherwise - // any existing content will be left untouched and the unpack stage will exit silently. - // As additional side effect, give both this option and SnapshotRoot to make each - // context try to unpack the snapshot only once. - Exclusive bool +func (o *Options) Warn(msg string, args ...interface{}) { + if o.Alerter != nil { + o.Alerter.Printf("WARNING: "+msg, args...) + } } -// WithChroot allows to override the root directory ghw uses. -func WithChroot(dir string) *Option { - return &Option{Chroot: &dir} -} +type Option func(opts *Options) -// WithSnapshot sets snapshot-processing options for a ghw run -func WithSnapshot(opts SnapshotOptions) *Option { - return &Option{ - Snapshot: &opts, +// WithChroot allows to override the root directory ghw uses. +func WithChroot(dir string) Option { + return func(opts *Options) { + opts.Chroot = dir } } // WithAlerter sets alerting options for ghw -func WithAlerter(alerter Alerter) *Option { - return &Option{ - Alerter: alerter, +// +// DEPRECATED. Use `pkg/context.WithDisableWarnings` +func WithAlerter(alerter Alerter) Option { + return func(opts *Options) { + opts.Alerter = alerter } } // WithNullAlerter sets No-op alerting options for ghw -func WithNullAlerter() *Option { - return &Option{ - Alerter: NullAlerter, +// +// DEPRECATED. Use `pkg/context.WithDisableWarnings` +func WithNullAlerter() Option { + return func(opts *Options) { + opts.Alerter = NullAlerter } } -// WithDisableTools sets enables or prohibts ghw to call external tools to discover hardware capabilities. -func WithDisableTools() *Option { - false_ := false - return &Option{EnableTools: &false_} +// WithDisableTools revents ghw from calling external tools to discover +// hardware capabilities. +// +// DEPRECATED. Use `pkg/context.WithDisableTools` +func WithDisableTools() Option { + return func(opts *Options) { + opts.DisableTools = true + } +} + +// WithPCIDB allows you to provide a custom instance of the PCI database (pcidb.PCIDB) +// to ghw. This is useful if you want to use a preloaded or specially configured +// PCI database, such as one created with custom pcidb.WithOption settings, instead +// of letting ghw load the PCI database automatically. +// +// DEPRECATED. Use `pkg/context.WithPCIDB` +func WithPCIDB(pcidb *pcidb.PCIDB) Option { + return func(opts *Options) { + opts.PCIDB = pcidb + } } // PathOverrides is a map, keyed by the string name of a mount path, of override paths type PathOverrides map[string]string // WithPathOverrides supplies path-specific overrides for the context -func WithPathOverrides(overrides PathOverrides) *Option { - return &Option{ - PathOverrides: overrides, +// +// DEPRECATED. Use `pkg/context.WithPathOverrides` +func WithPathOverrides(overrides PathOverrides) Option { + return func(opts *Options) { + opts.PathOverrides = overrides } } -// There is intentionally no Option related to GHW_SNAPSHOT_PRESERVE because we see that as -// a debug/troubleshoot aid more something users wants to do regularly. -// Hence we allow that only via the environment variable for the time being. - -// Merge accepts one or more Options and merges them together, returning the -// merged Option -func Merge(opts ...*Option) *Option { - merged := &Option{} - for _, opt := range opts { - if opt.Chroot != nil { - merged.Chroot = opt.Chroot - } - if opt.Snapshot != nil { - merged.Snapshot = opt.Snapshot - } - if opt.Alerter != nil { - merged.Alerter = opt.Alerter - } - if opt.EnableTools != nil { - merged.EnableTools = opt.EnableTools - } - // intentionally only programmatically - if opt.PathOverrides != nil { - merged.PathOverrides = opt.PathOverrides - } - if opt.Context != nil { - merged.Context = opt.Context - } - } - // Set the default value if missing from mergeOpts - if merged.Chroot == nil { - chroot := EnvOrDefaultChroot() - merged.Chroot = &chroot - } - if merged.Alerter == nil { - merged.Alerter = EnvOrDefaultAlerter() - } - if merged.Snapshot == nil { - snapRoot := EnvOrDefaultSnapshotRoot() - merged.Snapshot = &SnapshotOptions{ - Path: EnvOrDefaultSnapshotPath(), - Root: &snapRoot, - Exclusive: EnvOrDefaultSnapshotExclusive(), - } - } - if merged.EnableTools == nil { - enabled := EnvOrDefaultTools() - merged.EnableTools = &enabled +// FromEnv returns an Options populated from the environs or default option +// values +// +// DEPRECATED. Use `pkg/context.FromEnv` +func FromEnv() *Options { + return &Options{ + Chroot: EnvOrDefaultChroot(), + DisableTools: EnvOrDefaultDisableTools(), } - return merged } diff --git a/vendor/github.com/jaypipes/ghw/pkg/pci/pci.go b/vendor/github.com/jaypipes/ghw/pkg/pci/pci.go index 55cc1eacf..38c8fcd54 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/pci/pci.go +++ b/vendor/github.com/jaypipes/ghw/pkg/pci/pci.go @@ -12,20 +12,22 @@ import ( "github.com/jaypipes/pcidb" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/topology" "github.com/jaypipes/ghw/pkg/util" ) type Device struct { // The PCI address of the device - Address string `json:"address"` - Vendor *pcidb.Vendor `json:"vendor"` - Product *pcidb.Product `json:"product"` - Revision string `json:"revision"` - Subsystem *pcidb.Product `json:"subsystem"` + Address string `json:"address"` + // The PCI address of the parent device + ParentAddress string `json:"parent_address"` + Vendor *pcidb.Vendor `json:"vendor"` + Product *pcidb.Product `json:"product"` + Revision string `json:"revision"` + Subsystem *pcidb.Product `json:"subsystem"` // optional subvendor/sub-device information Class *pcidb.Class `json:"class"` // optional sub-class for the device @@ -36,6 +38,9 @@ type Device struct { // architecture is not NUMA. Node *topology.Node `json:"node,omitempty"` Driver string `json:"driver"` + // for IOMMU Groups see also: + // https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/7/html/virtualization_deployment_and_administration_guide/sect-iommu-deep-dive + IOMMUGroup string `json:"iommu_group"` } type devIdent struct { @@ -44,15 +49,17 @@ type devIdent struct { } type devMarshallable struct { - Driver string `json:"driver"` - Address string `json:"address"` - Vendor devIdent `json:"vendor"` - Product devIdent `json:"product"` - Revision string `json:"revision"` - Subsystem devIdent `json:"subsystem"` - Class devIdent `json:"class"` - Subclass devIdent `json:"subclass"` - Interface devIdent `json:"programming_interface"` + Driver string `json:"driver"` + Address string `json:"address"` + ParentAddress string `json:"parent_address"` + Vendor devIdent `json:"vendor"` + Product devIdent `json:"product"` + Revision string `json:"revision"` + Subsystem devIdent `json:"subsystem"` + Class devIdent `json:"class"` + Subclass devIdent `json:"subclass"` + Interface devIdent `json:"programming_interface"` + IOMMUGroup string `json:"iommu_group"` } // NOTE(jaypipes) Device has a custom JSON marshaller because we don't want @@ -61,8 +68,9 @@ type devMarshallable struct { // human-readable name of the vendor, product, class, etc. func (d *Device) MarshalJSON() ([]byte, error) { dm := devMarshallable{ - Driver: d.Driver, - Address: d.Address, + Driver: d.Driver, + Address: d.Address, + ParentAddress: d.ParentAddress, Vendor: devIdent{ ID: d.Vendor.ID, Name: d.Vendor.Name, @@ -88,6 +96,7 @@ func (d *Device) MarshalJSON() ([]byte, error) { ID: d.ProgrammingInterface.ID, Name: d.ProgrammingInterface.Name, }, + IOMMUGroup: d.IOMMUGroup, } return json.Marshal(dm) } @@ -118,7 +127,6 @@ func (d *Device) String() string { type Info struct { db *pcidb.PCIDB arch topology.Architecture - ctx *context.Context // All PCI devices on the host system Devices []*Device } @@ -129,36 +137,30 @@ func (i *Info) String() string { // New returns a pointer to an Info struct that contains information about the // PCI devices on the host system -func New(opts ...*option.Option) (*Info, error) { - merged := option.Merge(opts...) - ctx := context.New(merged) +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) // by default we don't report NUMA information; // we will only if are sure we are running on NUMA architecture info := &Info{ - arch: topology.ArchitectureSMP, - ctx: ctx, + arch: topology.ArchitectureSMP, // default to SMP } - - // we do this trick because we need to make sure ctx.Setup() gets - // a chance to run before any subordinate package is created reusing - // our context. - loadDetectingTopology := func() error { - topo, err := topology.New(context.WithContext(ctx)) - if err == nil { - info.arch = topo.Architecture - } else { - ctx.Warn("error detecting system topology: %v", err) - } - return info.load() - } - - var err error - if context.Exists(merged) { - err = loadDetectingTopology() + // Skip topology detection if requested to reduce memory consumption + if !config.TopologyEnabled(ctx) { + log.Warn( + ctx, "topology detection disabled, assuming SMP architecture", + ) } else { - err = ctx.Do(loadDetectingTopology) + topo, err := topology.New(ctx) + if err != nil { + return nil, fmt.Errorf( + "failed to initialize PCI info due to failure to initialize "+ + "Topology info: %w", + err, + ) + } + info.arch = topo.Architecture } - if err != nil { + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -183,11 +185,11 @@ type pciPrinter struct { // YAMLString returns a string with the PCI information formatted as YAML // under a top-level "pci:" key func (i *Info) YAMLString() string { - return marshal.SafeYAML(i.ctx, pciPrinter{i}) + return marshal.SafeYAML(pciPrinter{i}) } // JSONString returns a string with the PCI information formatted as JSON // under a top-level "pci:" key func (i *Info) JSONString(indent bool) string { - return marshal.SafeJSON(i.ctx, pciPrinter{i}, indent) + return marshal.SafeJSON(pciPrinter{i}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/pci/pci_linux.go b/vendor/github.com/jaypipes/ghw/pkg/pci/pci_linux.go index a96166879..f029dcf47 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/pci/pci_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/pci/pci_linux.go @@ -6,15 +6,15 @@ package pci import ( + "context" "os" "path/filepath" "strings" "github.com/jaypipes/pcidb" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" "github.com/jaypipes/ghw/pkg/linuxpath" - "github.com/jaypipes/ghw/pkg/option" pciaddr "github.com/jaypipes/ghw/pkg/pci/address" "github.com/jaypipes/ghw/pkg/topology" "github.com/jaypipes/ghw/pkg/util" @@ -25,31 +25,23 @@ const ( modAliasExpectedLength = 54 ) -func (i *Info) load() error { - // when consuming snapshots - most notably, but not only, in tests, - // the context pkg forces the chroot value to the unpacked snapshot root. - // This is intentional, intentionally transparent and ghw is prepared to handle this case. - // However, `pcidb` is not. It doesn't know about ghw snaphots, nor it should. - // so we need to complicate things a bit. If the user explicitely supplied - // a chroot option, then we should honor it all across the stack, and passing down - // the chroot to pcidb is the right thing to do. If, however, the chroot was - // implcitely set by snapshot support, then this must be consumed by ghw only. - // In this case we should NOT pass it down to pcidb. - chroot := i.ctx.Chroot - if i.ctx.SnapshotPath != "" { - chroot = option.DefaultChroot +func (i *Info) load(ctx context.Context) error { + pcidbOpt := &pcidb.WithOption{} + if path := os.Getenv("PCIDB_PATH"); path != "" { + pcidbOpt = pcidb.WithPath(path) } - db, err := pcidb.New(pcidb.WithChroot(chroot)) - if err != nil { - return err + if i.db == nil { + db, err := pcidb.New(pcidbOpt) + if err != nil { + return err + } + i.db = db } - i.db = db - i.Devices = i.getDevices() + i.Devices = i.getDevices(ctx) return nil } -func getDeviceModaliasPath(ctx *context.Context, pciAddr *pciaddr.Address) string { - paths := linuxpath.New(ctx) +func getDeviceModaliasPath(paths *linuxpath.Paths, pciAddr *pciaddr.Address) string { return filepath.Join( paths.SysBusPciDevices, pciAddr.String(), @@ -57,8 +49,7 @@ func getDeviceModaliasPath(ctx *context.Context, pciAddr *pciaddr.Address) strin ) } -func getDeviceRevision(ctx *context.Context, pciAddr *pciaddr.Address) string { - paths := linuxpath.New(ctx) +func getDeviceRevision(paths *linuxpath.Paths, pciAddr *pciaddr.Address) string { revisionPath := filepath.Join( paths.SysBusPciDevices, pciAddr.String(), @@ -75,7 +66,7 @@ func getDeviceRevision(ctx *context.Context, pciAddr *pciaddr.Address) string { return strings.TrimSpace(string(revision)) } -func getDeviceNUMANode(ctx *context.Context, pciAddr *pciaddr.Address) *topology.Node { +func getDeviceNUMANode(ctx context.Context, pciAddr *pciaddr.Address) *topology.Node { paths := linuxpath.New(ctx) numaNodePath := filepath.Join(paths.SysBusPciDevices, pciAddr.String(), "numa_node") @@ -93,8 +84,34 @@ func getDeviceNUMANode(ctx *context.Context, pciAddr *pciaddr.Address) *topology } } -func getDeviceDriver(ctx *context.Context, pciAddr *pciaddr.Address) string { - paths := linuxpath.New(ctx) +func getDeviceIommuGroup(paths *linuxpath.Paths, pciAddr *pciaddr.Address) string { + iommuGroupPath := filepath.Join(paths.SysBusPciDevices, pciAddr.String(), "iommu_group") + + dest, err := os.Readlink(iommuGroupPath) + if err != nil { + return "" + } + return filepath.Base(dest) +} + +func getDeviceParentAddress(paths *linuxpath.Paths, pciAddr *pciaddr.Address) string { + devPath := filepath.Join(paths.SysBusPciDevices, pciAddr.String()) + + dest, err := os.Readlink(devPath) + if err != nil { + return "" + } + + parentAddr := filepath.Base(filepath.Dir(dest)) + + if pciaddr.FromString(parentAddr) == nil { + return "" + } + + return parentAddr +} + +func getDeviceDriver(paths *linuxpath.Paths, pciAddr *pciaddr.Address) string { driverPath := filepath.Join(paths.SysBusPciDevices, pciAddr.String(), "driver") if _, err := os.Stat(driverPath); err != nil { @@ -299,37 +316,7 @@ func findPCIProgrammingInterface( // GetDevice returns a pointer to a Device struct that describes the PCI // device at the requested address. If no such device could be found, returns nil. func (info *Info) GetDevice(address string) *Device { - // check cached data first - if dev := info.lookupDevice(address); dev != nil { - return dev - } - - pciAddr := pciaddr.FromString(address) - if pciAddr == nil { - info.ctx.Warn("error parsing the pci address %q", address) - return nil - } - - // no cached data, let's get the information from system. - fp := getDeviceModaliasPath(info.ctx, pciAddr) - if fp == "" { - info.ctx.Warn("error finding modalias info for device %q", address) - return nil - } - - modaliasInfo := parseModaliasFile(fp) - if modaliasInfo == nil { - info.ctx.Warn("error parsing modalias info for device %q", address) - return nil - } - - device := info.getDeviceFromModaliasInfo(address, modaliasInfo) - device.Revision = getDeviceRevision(info.ctx, pciAddr) - if info.arch == topology.ArchitectureNUMA { - device.Node = getDeviceNUMANode(info.ctx, pciAddr) - } - device.Driver = getDeviceDriver(info.ctx, pciAddr) - return device + return info.lookupDevice(address) } // ParseDevice returns a pointer to a Device given its describing data. @@ -386,8 +373,8 @@ func (info *Info) getDeviceFromModaliasInfo( // getDevices returns a list of pointers to Device structs present on the // host system -func (info *Info) getDevices() []*Device { - paths := linuxpath.New(info.ctx) +func (info *Info) getDevices(ctx context.Context) []*Device { + paths := linuxpath.New(ctx) devs := make([]*Device, 0) // We scan the /sys/bus/pci/devices directory which contains a collection // of symlinks. The names of the symlinks are all the known PCI addresses @@ -395,18 +382,39 @@ func (info *Info) getDevices() []*Device { // address and append to the returned array. links, err := os.ReadDir(paths.SysBusPciDevices) if err != nil { - info.ctx.Warn("failed to read /sys/bus/pci/devices") + log.Warn(ctx, "failed to read /sys/bus/pci/devices") return nil } - var dev *Device for _, link := range links { - addr := link.Name() - dev = info.GetDevice(addr) - if dev == nil { - info.ctx.Warn("failed to get device information for PCI address %s", addr) - } else { - devs = append(devs, dev) + address := link.Name() + pciAddr := pciaddr.FromString(address) + if pciAddr == nil { + log.Warn(ctx, "error parsing the pci address %q", address) + return nil + } + + // no cached data, let's get the information from system. + fp := getDeviceModaliasPath(paths, pciAddr) + if fp == "" { + log.Warn(ctx, "error finding modalias info for device %q", address) + return nil + } + + modaliasInfo := parseModaliasFile(fp) + if modaliasInfo == nil { + log.Warn(ctx, "error parsing modalias info for device %q", address) + return nil + } + + device := info.getDeviceFromModaliasInfo(address, modaliasInfo) + device.Revision = getDeviceRevision(paths, pciAddr) + if info.arch == topology.ArchitectureNUMA { + device.Node = getDeviceNUMANode(ctx, pciAddr) } + device.Driver = getDeviceDriver(paths, pciAddr) + device.ParentAddress = getDeviceParentAddress(paths, pciAddr) + device.IOMMUGroup = getDeviceIommuGroup(paths, pciAddr) + devs = append(devs, device) } return devs } diff --git a/vendor/github.com/jaypipes/ghw/pkg/pci/pci_stub.go b/vendor/github.com/jaypipes/ghw/pkg/pci/pci_stub.go index 9ebb396d2..69e33c3c7 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/pci/pci_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/pci/pci_stub.go @@ -9,12 +9,13 @@ package pci import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("pciFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/product/product.go b/vendor/github.com/jaypipes/ghw/pkg/product/product.go index 83d6541d3..f1a1d1897 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/product/product.go +++ b/vendor/github.com/jaypipes/ghw/pkg/product/product.go @@ -7,15 +7,13 @@ package product import ( - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/config" "github.com/jaypipes/ghw/pkg/marshal" - "github.com/jaypipes/ghw/pkg/option" "github.com/jaypipes/ghw/pkg/util" ) // Info defines product information type Info struct { - ctx *context.Context Family string `json:"family"` Name string `json:"name"` Vendor string `json:"vendor"` @@ -68,10 +66,10 @@ func (i *Info) String() string { // New returns a pointer to a Info struct containing information // about the host's product -func New(opts ...*option.Option) (*Info, error) { - ctx := context.New(opts...) - info := &Info{ctx: ctx} - if err := ctx.Do(info.load); err != nil { +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { return nil, err } return info, nil @@ -86,11 +84,11 @@ type productPrinter struct { // YAMLString returns a string with the product information formatted as YAML // under a top-level "dmi:" key func (info *Info) YAMLString() string { - return marshal.SafeYAML(info.ctx, productPrinter{info}) + return marshal.SafeYAML(productPrinter{info}) } // JSONString returns a string with the product information formatted as JSON // under a top-level "product:" key func (info *Info) JSONString(indent bool) string { - return marshal.SafeJSON(info.ctx, productPrinter{info}, indent) + return marshal.SafeJSON(productPrinter{info}, indent) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/product/product_linux.go b/vendor/github.com/jaypipes/ghw/pkg/product/product_linux.go index 36b6b4471..91adb5e9e 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/product/product_linux.go +++ b/vendor/github.com/jaypipes/ghw/pkg/product/product_linux.go @@ -6,18 +6,19 @@ package product import ( + "context" + "github.com/jaypipes/ghw/pkg/linuxdmi" ) -func (i *Info) load() error { - - i.Family = linuxdmi.Item(i.ctx, "product_family") - i.Name = linuxdmi.Item(i.ctx, "product_name") - i.Vendor = linuxdmi.Item(i.ctx, "sys_vendor") - i.SerialNumber = linuxdmi.Item(i.ctx, "product_serial") - i.UUID = linuxdmi.Item(i.ctx, "product_uuid") - i.SKU = linuxdmi.Item(i.ctx, "product_sku") - i.Version = linuxdmi.Item(i.ctx, "product_version") +func (i *Info) load(ctx context.Context) error { + i.Family = linuxdmi.Item(ctx, "product_family") + i.Name = linuxdmi.Item(ctx, "product_name") + i.Vendor = linuxdmi.Item(ctx, "sys_vendor") + i.SerialNumber = linuxdmi.Item(ctx, "product_serial") + i.UUID = linuxdmi.Item(ctx, "product_uuid") + i.SKU = linuxdmi.Item(ctx, "product_sku") + i.Version = linuxdmi.Item(ctx, "product_version") return nil } diff --git a/vendor/github.com/jaypipes/ghw/pkg/product/product_stub.go b/vendor/github.com/jaypipes/ghw/pkg/product/product_stub.go index 8fc9724fb..221335940 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/product/product_stub.go +++ b/vendor/github.com/jaypipes/ghw/pkg/product/product_stub.go @@ -9,11 +9,12 @@ package product import ( + "context" "runtime" "github.com/pkg/errors" ) -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { return errors.New("productFillInfo not implemented on " + runtime.GOOS) } diff --git a/vendor/github.com/jaypipes/ghw/pkg/product/product_windows.go b/vendor/github.com/jaypipes/ghw/pkg/product/product_windows.go index c919cb0f6..2d2a83753 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/product/product_windows.go +++ b/vendor/github.com/jaypipes/ghw/pkg/product/product_windows.go @@ -6,7 +6,9 @@ package product import ( - "github.com/StackExchange/wmi" + "context" + + "github.com/yusufpapurcu/wmi" "github.com/jaypipes/ghw/pkg/util" ) @@ -24,7 +26,7 @@ type win32Product struct { UUID *string } -func (i *Info) load() error { +func (i *Info) load(ctx context.Context) error { // Getting data from WMI var win32ProductDescriptions []win32Product // Assuming the first product is the host... diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree.go deleted file mode 100644 index 020e7e673..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree.go +++ /dev/null @@ -1,198 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "errors" - "os" - "path/filepath" - "strings" -) - -// Attempting to tar up pseudofiles like /proc/cpuinfo is an exercise in -// futility. Notably, the pseudofiles, when read by syscalls, do not return the -// number of bytes read. This causes the tar writer to write zero-length files. -// -// Instead, it is necessary to build a directory structure in a tmpdir and -// create actual files with copies of the pseudofile contents - -// CloneTreeInto copies all the pseudofiles that ghw will consume into the root -// `scratchDir`, preserving the hieratchy. -func CloneTreeInto(scratchDir string) error { - err := setupScratchDir(scratchDir) - if err != nil { - return err - } - fileSpecs := ExpectedCloneContent() - return CopyFilesInto(fileSpecs, scratchDir, nil) -} - -// ExpectedCloneContent return a slice of glob patterns which represent the pseudofiles -// ghw cares about. -// The intended usage of this function is to validate a clone tree, checking that the -// content matches the expectations. -// Beware: the content is host-specific, because the content pertaining some subsystems, -// most notably PCI, is host-specific and unpredictable. -func ExpectedCloneContent() []string { - fileSpecs := ExpectedCloneStaticContent() - fileSpecs = append(fileSpecs, ExpectedCloneNetContent()...) - fileSpecs = append(fileSpecs, ExpectedClonePCIContent()...) - fileSpecs = append(fileSpecs, ExpectedCloneGPUContent()...) - return fileSpecs -} - -// ValidateClonedTree checks the content of a cloned tree, whose root is `clonedDir`, -// against a slice of glob specs which must be included in the cloned tree. -// Is not wrong, and this functions doesn't enforce this, that the cloned tree includes -// more files than the necessary; ghw will just ignore the files it doesn't care about. -// Returns a slice of glob patters expected (given) but not found in the cloned tree, -// and the error during the validation (if any). -func ValidateClonedTree(fileSpecs []string, clonedDir string) ([]string, error) { - missing := []string{} - for _, fileSpec := range fileSpecs { - matches, err := filepath.Glob(filepath.Join(clonedDir, fileSpec)) - if err != nil { - return missing, err - } - if len(matches) == 0 { - missing = append(missing, fileSpec) - } - } - return missing, nil -} - -// CopyFileOptions allows to finetune the behaviour of the CopyFilesInto function -type CopyFileOptions struct { - // IsSymlinkFn allows to control the behaviour when handling a symlink. - // If this hook returns true, the source file is treated as symlink: the cloned - // tree will thus contain a symlink, with its path adjusted to match the relative - // path inside the cloned tree. If return false, the symlink will be deferred. - // The easiest use case of this hook is if you want to avoid symlinks in your cloned - // tree (having duplicated content). In this case you can just add a function - // which always return false. - IsSymlinkFn func(path string, info os.FileInfo) bool - // ShouldCreateDirFn allows to control if empty directories listed as clone - // content should be created or not. When creating snapshots, empty directories - // are most often useless (but also harmless). Because of this, directories are only - // created as side effect of copying the files which are inside, and thus directories - // are never empty. The only notable exception are device driver on linux: in this - // case, for a number of technical/historical reasons, we care about the directory - // name, but not about the files which are inside. - // Hence, this is the only case on which ghw clones empty directories. - ShouldCreateDirFn func(path string, info os.FileInfo) bool -} - -// CopyFilesInto copies all the given glob files specs in the given `destDir` directory, -// preserving the directory structure. This means you can provide a deeply nested filespec -// like -// - /some/deeply/nested/file* -// and you DO NOT need to build the tree incrementally like -// - /some/ -// - /some/deeply/ -// ... -// all glob patterns supported in `filepath.Glob` are supported. -func CopyFilesInto(fileSpecs []string, destDir string, opts *CopyFileOptions) error { - if opts == nil { - opts = &CopyFileOptions{ - IsSymlinkFn: isSymlink, - ShouldCreateDirFn: isDriversDir, - } - } - for _, fileSpec := range fileSpecs { - trace("copying spec: %q\n", fileSpec) - matches, err := filepath.Glob(fileSpec) - if err != nil { - return err - } - if err := copyFileTreeInto(matches, destDir, opts); err != nil { - return err - } - } - return nil -} - -func copyFileTreeInto(paths []string, destDir string, opts *CopyFileOptions) error { - for _, path := range paths { - trace(" copying path: %q\n", path) - baseDir := filepath.Dir(path) - if err := os.MkdirAll(filepath.Join(destDir, baseDir), os.ModePerm); err != nil { - return err - } - - fi, err := os.Lstat(path) - if err != nil { - return err - } - // directories must be listed explicitly and created separately. - // In the future we may want to expose this decision as hook point in - // CopyFileOptions, when clear use cases emerge. - destPath := filepath.Join(destDir, path) - if fi.IsDir() { - if opts.ShouldCreateDirFn(path, fi) { - if err := os.MkdirAll(destPath, os.ModePerm); err != nil { - return err - } - } else { - trace("expanded glob path %q is a directory - skipped\n", path) - } - continue - } - if opts.IsSymlinkFn(path, fi) { - trace(" copying link: %q -> %q\n", path, destPath) - if err := copyLink(path, destPath); err != nil { - return err - } - } else { - trace(" copying file: %q -> %q\n", path, destPath) - if err := copyPseudoFile(path, destPath); err != nil && !errors.Is(err, os.ErrPermission) { - return err - } - } - } - return nil -} - -func isSymlink(path string, fi os.FileInfo) bool { - return fi.Mode()&os.ModeSymlink != 0 -} - -func isDriversDir(path string, fi os.FileInfo) bool { - return strings.Contains(path, "drivers") -} - -func copyLink(path, targetPath string) error { - target, err := os.Readlink(path) - if err != nil { - return err - } - trace(" symlink %q -> %q\n", target, targetPath) - if err := os.Symlink(target, targetPath); err != nil { - if errors.Is(err, os.ErrExist) { - return nil - } - return err - } - - return nil -} - -func copyPseudoFile(path, targetPath string) error { - buf, err := os.ReadFile(path) - if err != nil { - return err - } - trace("creating %s\n", targetPath) - f, err := os.Create(targetPath) - if err != nil { - return err - } - if _, err = f.Write(buf); err != nil { - return err - } - f.Close() - return nil -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_block_linux.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_block_linux.go deleted file mode 100644 index f692d4137..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_block_linux.go +++ /dev/null @@ -1,220 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "errors" - "os" - "path/filepath" - "strings" -) - -func createBlockDevices(buildDir string) error { - // Grab all the block device pseudo-directories from /sys/block symlinks - // (excluding loopback devices) and inject them into our build filesystem - // with all but the circular symlink'd subsystem directories - devLinks, err := os.ReadDir("/sys/block") - if err != nil { - return err - } - for _, devLink := range devLinks { - dname := devLink.Name() - if strings.HasPrefix(dname, "loop") { - continue - } - devPath := filepath.Join("/sys/block", dname) - trace("processing block device %q\n", devPath) - - // from the sysfs layout, we know this is always a symlink - linkContentPath, err := os.Readlink(devPath) - if err != nil { - return err - } - trace("link target for block device %q is %q\n", devPath, linkContentPath) - - // Create a symlink in our build filesystem that is a directory - // pointing to the actual device bus path where the block device's - // information directory resides - linkPath := filepath.Join(buildDir, "sys/block", dname) - linkTargetPath := filepath.Join( - buildDir, - "sys/block", - strings.TrimPrefix(linkContentPath, string(os.PathSeparator)), - ) - trace("creating device directory %s\n", linkTargetPath) - if err = os.MkdirAll(linkTargetPath, os.ModePerm); err != nil { - return err - } - - trace("linking device directory %s to %s\n", linkPath, linkContentPath) - // Make sure the link target is a relative path! - // if we use absolute path, the link target will be an absolute path starting - // with buildDir, hence the snapshot will contain broken link. - // Otherwise, the unpack directory will never have the same prefix of buildDir! - if err = os.Symlink(linkContentPath, linkPath); err != nil { - return err - } - // Now read the source block device directory and populate the - // newly-created target link in the build directory with the - // appropriate block device pseudofiles - srcDeviceDir := filepath.Join( - "/sys/block", - strings.TrimPrefix(linkContentPath, string(os.PathSeparator)), - ) - trace("creating device directory %q from %q\n", linkTargetPath, srcDeviceDir) - if err = createBlockDeviceDir(linkTargetPath, srcDeviceDir); err != nil { - return err - } - } - return nil -} - -func createBlockDeviceDir(buildDeviceDir string, srcDeviceDir string) error { - // Populate the supplied directory (in our build filesystem) with all the - // appropriate information pseudofile contents for the block device. - devName := filepath.Base(srcDeviceDir) - devFiles, err := os.ReadDir(srcDeviceDir) - if err != nil { - return err - } - for _, f := range devFiles { - fname := f.Name() - fp := filepath.Join(srcDeviceDir, fname) - fi, err := os.Lstat(fp) - if err != nil { - return err - } - if fi.Mode()&os.ModeSymlink != 0 { - // Ignore any symlinks in the deviceDir since they simply point to - // either self-referential links or information we aren't - // interested in like "subsystem" - continue - } else if fi.IsDir() { - if strings.HasPrefix(fname, devName) { - // We're interested in are the directories that begin with the - // block device name. These are directories with information - // about the partitions on the device - buildPartitionDir := filepath.Join( - buildDeviceDir, fname, - ) - srcPartitionDir := filepath.Join( - srcDeviceDir, fname, - ) - trace("creating partition directory %s\n", buildPartitionDir) - err = os.MkdirAll(buildPartitionDir, os.ModePerm) - if err != nil { - return err - } - err = createPartitionDir(buildPartitionDir, srcPartitionDir) - if err != nil { - return err - } - } - } else if fi.Mode().IsRegular() { - // Regular files in the block device directory are both regular and - // pseudofiles containing information such as the size (in sectors) - // and whether the device is read-only - buf, err := os.ReadFile(fp) - if err != nil { - if errors.Is(err, os.ErrPermission) { - // example: /sys/devices/virtual/block/zram0/compact is 0400 - trace("permission denied reading %q - skipped\n", fp) - continue - } - return err - } - targetPath := filepath.Join(buildDeviceDir, fname) - trace("creating %s\n", targetPath) - f, err := os.Create(targetPath) - if err != nil { - return err - } - if _, err = f.Write(buf); err != nil { - return err - } - f.Close() - } - } - // There is a special file $DEVICE_DIR/queue/rotational that, for some hard - // drives, contains a 1 or 0 indicating whether the device is a spinning - // disk or not - srcQueueDir := filepath.Join( - srcDeviceDir, - "queue", - ) - buildQueueDir := filepath.Join( - buildDeviceDir, - "queue", - ) - err = os.MkdirAll(buildQueueDir, os.ModePerm) - if err != nil { - return err - } - fp := filepath.Join(srcQueueDir, "rotational") - buf, err := os.ReadFile(fp) - if err != nil { - return err - } - targetPath := filepath.Join(buildQueueDir, "rotational") - trace("creating %s\n", targetPath) - f, err := os.Create(targetPath) - if err != nil { - return err - } - if _, err = f.Write(buf); err != nil { - return err - } - f.Close() - - return nil -} - -func createPartitionDir(buildPartitionDir string, srcPartitionDir string) error { - // Populate the supplied directory (in our build filesystem) with all the - // appropriate information pseudofile contents for the partition. - partFiles, err := os.ReadDir(srcPartitionDir) - if err != nil { - return err - } - for _, f := range partFiles { - fname := f.Name() - fp := filepath.Join(srcPartitionDir, fname) - fi, err := os.Lstat(fp) - if err != nil { - return err - } - if fi.Mode()&os.ModeSymlink != 0 { - // Ignore any symlinks in the partition directory since they simply - // point to information we aren't interested in like "subsystem" - continue - } else if fi.IsDir() { - // The subdirectories in the partition directory are not - // interesting for us. They have information about power events and - // traces - continue - } else if fi.Mode().IsRegular() { - // Regular files in the block device directory are both regular and - // pseudofiles containing information such as the size (in sectors) - // and whether the device is read-only - buf, err := os.ReadFile(fp) - if err != nil { - return err - } - targetPath := filepath.Join(buildPartitionDir, fname) - trace("creating %s\n", targetPath) - f, err := os.Create(targetPath) - if err != nil { - return err - } - if _, err = f.Write(buf); err != nil { - return err - } - f.Close() - } - } - return nil -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_gpu_linux.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_gpu_linux.go deleted file mode 100644 index a26d6b01f..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_gpu_linux.go +++ /dev/null @@ -1,33 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "strings" -) - -// ExpectedCloneGPUContent returns a slice of strings pertaining to the GPU devices ghw -// cares about. We cannot use a static list because we want to grab only the first cardX data -// (see comment in pkg/gpu/gpu_linux.go) -// Additionally, we want to make sure to clone the backing device data. -func ExpectedCloneGPUContent() []string { - cardEntries := []string{ - "device", - } - - filterName := func(cardName string) bool { - if !strings.HasPrefix(cardName, "card") { - return false - } - if strings.ContainsRune(cardName, '-') { - return false - } - return true - } - - return cloneContentByClass("drm", cardEntries, filterName, filterNone) -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_linux.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_linux.go deleted file mode 100644 index 8191e80c4..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_linux.go +++ /dev/null @@ -1,109 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "os" - "path/filepath" -) - -func setupScratchDir(scratchDir string) error { - var createPaths = []string{ - "sys/block", - } - - for _, path := range createPaths { - if err := os.MkdirAll(filepath.Join(scratchDir, path), os.ModePerm); err != nil { - return err - } - } - - return createBlockDevices(scratchDir) -} - -// ExpectedCloneStaticContent return a slice of glob patterns which represent the pseudofiles -// ghw cares about, and which are independent from host specific topology or configuration, -// thus are safely represented by a static slice - e.g. they don't need to be discovered at runtime. -func ExpectedCloneStaticContent() []string { - return []string{ - "/proc/cpuinfo", - "/proc/meminfo", - "/proc/self/mounts", - "/sys/devices/system/cpu/cpu*/cache/index*/*", - "/sys/devices/system/cpu/cpu*/topology/*", - "/sys/devices/system/memory/block_size_bytes", - "/sys/devices/system/memory/memory*/online", - "/sys/devices/system/memory/memory*/state", - "/sys/devices/system/node/has_*", - "/sys/devices/system/node/online", - "/sys/devices/system/node/possible", - "/sys/devices/system/node/node*/cpu*", - "/sys/devices/system/node/node*/cpu*/online", - "/sys/devices/system/node/node*/distance", - "/sys/devices/system/node/node*/meminfo", - "/sys/devices/system/node/node*/memory*", - "/sys/devices/system/node/node*/hugepages/hugepages-*/*", - } -} - -type filterFunc func(string) bool - -// cloneContentByClass copies all the content related to a given device class -// (devClass), possibly filtering out devices whose name does NOT pass a -// filter (filterName). Each entry in `/sys/class/$CLASS` is actually a -// symbolic link. We can filter out entries depending on the link target. -// Each filter is a simple function which takes the entry name or the link -// target and must return true if the entry should be collected, false -// otherwise. Last, explicitly collect a list of attributes for each entry, -// given as list of glob patterns as `subEntries`. -// Return the final list of glob patterns to be collected. -func cloneContentByClass(devClass string, subEntries []string, filterName filterFunc, filterLink filterFunc) []string { - var fileSpecs []string - - // warning: don't use the context package here, this means not even the linuxpath package. - // TODO(fromani) remove the path duplication - sysClass := filepath.Join("sys", "class", devClass) - entries, err := os.ReadDir(sysClass) - if err != nil { - // we should not import context, hence we can't Warn() - return fileSpecs - } - for _, entry := range entries { - devName := entry.Name() - - if !filterName(devName) { - continue - } - - devPath := filepath.Join(sysClass, devName) - dest, err := os.Readlink(devPath) - if err != nil { - continue - } - - if !filterLink(dest) { - continue - } - - // so, first copy the symlink itself - fileSpecs = append(fileSpecs, devPath) - // now we have to clone the content of the actual entry - // related (and found into a subdir of) the backing hardware - // device - devData := filepath.Clean(filepath.Join(sysClass, dest)) - for _, subEntry := range subEntries { - fileSpecs = append(fileSpecs, filepath.Join(devData, subEntry)) - } - } - - return fileSpecs -} - -// filterNone allows all content, filtering out none of it -func filterNone(_ string) bool { - return true -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_net_linux.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_net_linux.go deleted file mode 100644 index 27b27573f..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_net_linux.go +++ /dev/null @@ -1,28 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "strings" -) - -// ExpectedCloneNetContent returns a slice of strings pertaning to the network interfaces ghw -// cares about. We cannot use a static list because we want to filter away the virtual devices, -// which ghw doesn't concern itself about. So we need to do some runtime discovery. -// Additionally, we want to make sure to clone the backing device data. -func ExpectedCloneNetContent() []string { - ifaceEntries := []string{ - "addr_assign_type", - // intentionally avoid to clone "address" to avoid to leak any host-idenfifiable data. - } - - filterLink := func(linkDest string) bool { - return !strings.Contains(linkDest, "devices/virtual/net") - } - - return cloneContentByClass("net", ifaceEntries, filterNone, filterLink) -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_pci_linux.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_pci_linux.go deleted file mode 100644 index e7aa7d265..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_pci_linux.go +++ /dev/null @@ -1,150 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "fmt" - "os" - "path/filepath" - - pciaddr "github.com/jaypipes/ghw/pkg/pci/address" -) - -const ( - // root directory: entry point to start scanning the PCI forest - // warning: don't use the context package here, this means not even the linuxpath package. - // TODO(fromani) remove the path duplication - sysBusPCIDir = "/sys/bus/pci/devices" -) - -// ExpectedClonePCIContent return a slice of glob patterns which represent the pseudofiles -// ghw cares about, pertaining to PCI devices only. -// Beware: the content is host-specific, because the PCI topology is host-dependent and unpredictable. -func ExpectedClonePCIContent() []string { - fileSpecs := []string{ - "/sys/bus/pci/drivers/*", - } - pciRoots := []string{ - sysBusPCIDir, - } - for { - if len(pciRoots) == 0 { - break - } - pciRoot := pciRoots[0] - pciRoots = pciRoots[1:] - specs, roots := scanPCIDeviceRoot(pciRoot) - pciRoots = append(pciRoots, roots...) - fileSpecs = append(fileSpecs, specs...) - } - return fileSpecs -} - -// scanPCIDeviceRoot reports a slice of glob patterns which represent the pseudofiles -// ghw cares about pertaining to all the PCI devices connected to the bus connected from the -// given root; usually (but not always) a CPU packages has 1+ PCI(e) roots, forming the first -// level; more PCI bridges are (usually) attached to this level, creating deep nested trees. -// hence we need to scan all possible roots, to make sure not to miss important devices. -// -// note about notifying errors. This function and its helper functions do use trace() everywhere -// to report recoverable errors, even though it would have been appropriate to use Warn(). -// This is unfortunate, and again a byproduct of the fact we cannot use context.Context to avoid -// circular dependencies. -// TODO(fromani): switch to Warn() as soon as we figure out how to break this circular dep. -func scanPCIDeviceRoot(root string) (fileSpecs []string, pciRoots []string) { - trace("scanning PCI device root %q\n", root) - - perDevEntries := []string{ - "class", - "device", - "driver", - "irq", - "local_cpulist", - "modalias", - "numa_node", - "revision", - "vendor", - } - entries, err := os.ReadDir(root) - if err != nil { - return []string{}, []string{} - } - for _, entry := range entries { - entryName := entry.Name() - if addr := pciaddr.FromString(entryName); addr == nil { - // doesn't look like a entry we care about - // This is by far and large the most likely path - // hence we should NOT trace/warn here. - continue - } - - entryPath := filepath.Join(root, entryName) - pciEntry, err := findPCIEntryFromPath(root, entryName) - if err != nil { - trace("error scanning %q: %v", entryName, err) - continue - } - - trace("PCI entry is %q\n", pciEntry) - fileSpecs = append(fileSpecs, entryPath) - for _, perNetEntry := range perDevEntries { - fileSpecs = append(fileSpecs, filepath.Join(pciEntry, perNetEntry)) - } - - if isPCIBridge(entryPath) { - trace("adding new PCI root %q\n", entryName) - pciRoots = append(pciRoots, pciEntry) - } - } - return fileSpecs, pciRoots -} - -func findPCIEntryFromPath(root, entryName string) (string, error) { - entryPath := filepath.Join(root, entryName) - fi, err := os.Lstat(entryPath) - if err != nil { - return "", fmt.Errorf("stat(%s) failed: %v\n", entryPath, err) - } - if fi.Mode()&os.ModeSymlink == 0 { - // regular file, nothing to resolve - return entryPath, nil - } - // resolve symlink - target, err := os.Readlink(entryPath) - trace("entry %q is symlink resolved to %q\n", entryPath, target) - if err != nil { - return "", fmt.Errorf("readlink(%s) failed: %v - skipped\n", entryPath, err) - } - return filepath.Clean(filepath.Join(root, target)), nil -} - -func isPCIBridge(entryPath string) bool { - subNodes, err := os.ReadDir(entryPath) - if err != nil { - // this is so unlikely we don't even return error. But we trace just in case. - trace("error scanning device entry path %q: %v", entryPath, err) - return false - } - for _, subNode := range subNodes { - if !subNode.IsDir() { - continue - } - if addr := pciaddr.FromString(subNode.Name()); addr != nil { - // we got an entry in the directory pertaining to this device - // which is a directory itself and it is named like a PCI address. - // Hence we infer the device we are considering is a PCI bridge of sorts. - // This is is indeed a bit brutal, but the only possible alternative - // (besides blindly copying everything in /sys/bus/pci/devices) is - // to detect the type of the device and pick only the bridges. - // This approach duplicates the logic within the `pci` subkpg - // - or forces us into awkward dep cycles, and has poorer forward - // compatibility. - return true - } - } - return false -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_stub.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_stub.go deleted file mode 100644 index af85a55b5..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/clonetree_stub.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build !linux -// +build !linux - -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -func setupScratchDir(scratchDir string) error { - return nil -} - -func ExpectedCloneStaticContent() []string { - return []string{} -} - -func ExpectedCloneGPUContent() []string { - return []string{} -} - -func ExpectedCloneNetContent() []string { - return []string{} -} - -func ExpectedClonePCIContent() []string { - return []string{} -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/pack.go b/vendor/github.com/jaypipes/ghw/pkg/snapshot/pack.go deleted file mode 100644 index 73820c94b..000000000 --- a/vendor/github.com/jaypipes/ghw/pkg/snapshot/pack.go +++ /dev/null @@ -1,111 +0,0 @@ -// -// Use and distribution licensed under the Apache license version 2. -// -// See the COPYING file in the root project directory for full text. -// - -package snapshot - -import ( - "archive/tar" - "compress/gzip" - "errors" - "fmt" - "io" - "os" - "path/filepath" -) - -// PackFrom creates the snapshot named `snapshotName` from the -// directory tree whose root is `sourceRoot`. -func PackFrom(snapshotName, sourceRoot string) error { - f, err := OpenDestination(snapshotName) - if err != nil { - return err - } - defer f.Close() - - return PackWithWriter(f, sourceRoot) -} - -// OpenDestination opens the `snapshotName` file for writing, bailing out -// if the file seems to exist and have existing content already. -// This is done to avoid accidental overwrites. -func OpenDestination(snapshotName string) (*os.File, error) { - f, err := os.OpenFile(snapshotName, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0600) - if err != nil { - if !errors.Is(err, os.ErrExist) { - return nil, err - } - fs, err := os.Stat(snapshotName) - if err != nil { - return nil, err - } - if fs.Size() > 0 { - return nil, fmt.Errorf("file %s already exists and is of size > 0", snapshotName) - } - f, err = os.OpenFile(snapshotName, os.O_WRONLY, 0600) - if err != nil { - return nil, err - } - } - return f, nil -} - -// PakcWithWriter creates a snapshot sending all the binary data to the -// given `fw` writer. The snapshot is made from the directory tree whose -// root is `sourceRoot`. -func PackWithWriter(fw io.Writer, sourceRoot string) error { - gzw := gzip.NewWriter(fw) - defer gzw.Close() - - tw := tar.NewWriter(gzw) - defer tw.Close() - - return createSnapshot(tw, sourceRoot) -} - -func createSnapshot(tw *tar.Writer, buildDir string) error { - return filepath.Walk(buildDir, func(path string, fi os.FileInfo, _ error) error { - if path == buildDir { - return nil - } - var link string - var err error - - if fi.Mode()&os.ModeSymlink != 0 { - trace("processing symlink %s\n", path) - link, err = os.Readlink(path) - if err != nil { - return err - } - } - - hdr, err := tar.FileInfoHeader(fi, link) - if err != nil { - return err - } - relPath, err := filepath.Rel(buildDir, path) - if err != nil { - return err - } - hdr.Name = relPath - - if err = tw.WriteHeader(hdr); err != nil { - return err - } - - switch hdr.Typeflag { - case tar.TypeReg, tar.TypeRegA: - f, err := os.Open(path) - if err != nil { - return err - } - defer f.Close() - if _, err = io.Copy(tw, f); err != nil { - return err - } - } - return nil - }) -} diff --git a/vendor/github.com/jaypipes/ghw/pkg/snapshot/testdata.tar.gz b/vendor/github.com/jaypipes/ghw/pkg/snapshot/testdata.tar.gz deleted file mode 100644 index edb26fbda33391756dfa941509fc5313d489f76a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 485 zcmVKX6UY9kwC`hFb3r0+H*{*{{pb2`uf7#{ zfjG&_qA-oAI&Yr@?)$%>QeyuP;k19-Z@b2r#n*vLf6my@Kb0&+{}6ubzw|^f_Sg6I z9|k|lsiKNRJdTst_ke=_*ZZ?&uHn?*KL57Axa_~s?VMYEf4~1;%WeMGIQ8$VZT68>JICV!_x>Wq z=YJTF_ILTZ;CB9F&;L`Q@cW-2p6Wjx9*94$;dK5Z?DMaN2>|CmA 0 { + str.WriteString(" ") + } + i++ + str.WriteString(k) + str.WriteString("=") + if needsQuotationMarks { + str.WriteString("\"") + } + str.WriteString(v) + if needsQuotationMarks { + str.WriteString("\"") + } + + } + + return str.String() +} + +// Info describes all network interface controllers (NICs) in the host system. +type Info struct { + Devices []*Device `json:"devices"` +} + +// String returns a short string with information about the networking on the +// host system. +func (i *Info) String() string { + return fmt.Sprintf( + "USB (%d USBs)", + len(i.Devices), + ) +} + +// New returns a pointer to an Info struct that contains information about the +// network interface controllers (NICs) on the host system +func New(args ...any) (*Info, error) { + ctx := config.ContextFromArgs(args...) + info := &Info{} + if err := info.load(ctx); err != nil { + return nil, err + } + return info, nil +} + +// simple private struct used to encapsulate usb information in a +// top-level "usb" YAML/JSON map/object key +type usbPrinter struct { + Info *Info `json:"usb"` +} + +// YAMLString returns a string with the net information formatted as YAML +// under a top-level "net:" key +func (i *Info) YAMLString() string { + return marshal.SafeYAML(usbPrinter{i}) +} + +// JSONString returns a string with the net information formatted as JSON +// under a top-level "net:" key +func (i *Info) JSONString(indent bool) string { + return marshal.SafeJSON(usbPrinter{i}, indent) +} diff --git a/vendor/github.com/jaypipes/ghw/pkg/usb/usb_linux.go b/vendor/github.com/jaypipes/ghw/pkg/usb/usb_linux.go new file mode 100644 index 000000000..87fa7ba53 --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/pkg/usb/usb_linux.go @@ -0,0 +1,116 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package usb + +import ( + "bufio" + "bytes" + "context" + "fmt" + "os" + "path/filepath" + "strings" + + "github.com/jaypipes/ghw/pkg/linuxpath" +) + +func (i *Info) load(ctx context.Context) error { + var errs []error + + i.Devices, errs = usbs(ctx) + + if len(errs) == 0 { + return nil + } + return fmt.Errorf("error(s) happened during reading usb info: %+v", errs) +} + +func fillUSBFromUevent(dir string, dev *Device) (err error) { + ueventFp, err := os.Open(filepath.Join(dir, "uevent")) + if err != nil { + return + } + defer func() { + err = ueventFp.Close() + }() + + sc := bufio.NewScanner(ueventFp) + for sc.Scan() { + line := sc.Text() + + splits := strings.SplitN(line, "=", 2) + if len(splits) != 2 { + continue + } + + key := strings.ToUpper(splits[0]) + val := splits[1] + + switch key { + case "DRIVER": + dev.Driver = val + case "TYPE": + dev.Type = val + case "PRODUCT": + splits := strings.SplitN(val, "/", 3) + if len(splits) != 3 { + continue + } + dev.VendorID = splits[0] + dev.ProductID = splits[1] + dev.RevisionID = splits[2] + } + } + return nil +} + +func slurp(path string) string { + bs, err := os.ReadFile(path) + if err != nil { + return "" + } + + return string(bytes.TrimSpace(bs)) +} + +func usbs(ctx context.Context) ([]*Device, []error) { + paths := linuxpath.New(ctx) + devs := make([]*Device, 0) + errs := []error{} + + usbDevicesDirs, err := os.ReadDir(paths.SysBusUsbDevices) + if err != nil { + return devs, []error{err} + } + + for _, dir := range usbDevicesDirs { + linkPath := filepath.Join(paths.SysBusUsbDevices, dir.Name()) + fullDir, err := os.Readlink(linkPath) + if err != nil { + continue + } + if !filepath.IsAbs(fullDir) { + fullDir, err = filepath.Abs(filepath.Join(paths.SysBusUsbDevices, fullDir)) + if err != nil { + continue + } + } + + dev := Device{} + + err = fillUSBFromUevent(fullDir, &dev) + if err != nil { + errs = append(errs, err) + } + + dev.Interface = slurp(filepath.Join(fullDir, "interface")) + dev.Product = slurp(filepath.Join(fullDir, "product")) + + devs = append(devs, &dev) + } + + return devs, errs +} diff --git a/vendor/github.com/jaypipes/ghw/pkg/usb/usb_stub.go b/vendor/github.com/jaypipes/ghw/pkg/usb/usb_stub.go new file mode 100644 index 000000000..6345fe063 --- /dev/null +++ b/vendor/github.com/jaypipes/ghw/pkg/usb/usb_stub.go @@ -0,0 +1,20 @@ +//go:build !linux +// +build !linux + +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package usb + +import ( + "context" + "runtime" + + "errors" +) + +func (i *Info) load(ctx context.Context) error { + return errors.New("usb load not implemented on " + runtime.GOOS) +} diff --git a/vendor/github.com/jaypipes/ghw/pkg/util/util.go b/vendor/github.com/jaypipes/ghw/pkg/util/util.go index 816aeb1b3..24e635a66 100644 --- a/vendor/github.com/jaypipes/ghw/pkg/util/util.go +++ b/vendor/github.com/jaypipes/ghw/pkg/util/util.go @@ -7,12 +7,13 @@ package util import ( + "context" "fmt" "os" "strconv" "strings" - "github.com/jaypipes/ghw/pkg/context" + "github.com/jaypipes/ghw/internal/log" ) const ( @@ -34,17 +35,17 @@ func SafeClose(c closer) { // -1 if there were file permissions or existence errors or if the contents // could not be successfully converted to an integer. In any error, a warning // message is printed to STDERR and -1 is returned. -func SafeIntFromFile(ctx *context.Context, path string) int { +func SafeIntFromFile(ctx context.Context, path string) int { msg := "failed to read int from file: %s\n" buf, err := os.ReadFile(path) if err != nil { - ctx.Warn(msg, err) + log.Warn(ctx, msg, err) return -1 } contents := strings.TrimSpace(string(buf)) res, err := strconv.Atoi(contents) if err != nil { - ctx.Warn(msg, err) + log.Warn(ctx, msg, err) return -1 } return res diff --git a/vendor/github.com/jaypipes/pcidb/README.md b/vendor/github.com/jaypipes/pcidb/README.md index 27485dca4..448cdab6d 100644 --- a/vendor/github.com/jaypipes/pcidb/README.md +++ b/vendor/github.com/jaypipes/pcidb/README.md @@ -4,10 +4,10 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/jaypipes/pcidb)](https://goreportcard.com/report/github.com/jaypipes/pcidb) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](CODE_OF_CONDUCT.md) -`pcidb` is a small Golang library for programmatic querying of PCI vendor, -product and class information. +`pcidb` is a small Go library for programmatic querying of PCI vendor, product +and class information. -We currently test `pcidb` on Linux, Windows and MacOSX. +We test `pcidb` on Linux, Windows and MacOSX. ## Usage @@ -18,12 +18,24 @@ product information. The `pcidb.New()` function returns a `pcidb.PCIDB` struct or an error if the PCI database could not be loaded. -> `pcidb`'s default behaviour is to first search for pci-ids DB files on the -> local host system in well-known filesystem paths. If `pcidb` cannot find a -> pci-ids DB file on the local host system, you can configure `pcidb` to fetch -> a current pci-ids DB file from the network. You can enable this -> network-fetching behaviour with the `pcidb.WithEnableNetworkFetch()` function -> or set the `PCIDB_ENABLE_NETWORK_FETCH` to a non-0 value. +```go +package main + +import ( + "fmt" + + "github.com/jaypipes/pcidb" +) + +func main() { + pci, err := pcidb.New() + if err != nil { + fmt.Printf("Error getting PCI info: %v", err) + } +} +``` + +> Learn about [how `pcidb` discovers `pci.ids` database files](#discovery). The `pcidb.PCIDB` struct contains a number of fields that may be queried for PCI information: @@ -42,27 +54,6 @@ PCI information: the term "product ID" in `pcidb` because it more accurately reflects what the identifier is for: a specific product line produced by the vendor. -### Overriding the root mountpoint `pcidb` uses - -The default root mountpoint that `pcidb` uses when looking for information -about the host system is `/`. So, for example, when looking up known PCI IDS DB -files on Linux, `pcidb` will attempt to discover a pciids DB file at -`/usr/share/misc/pci.ids`. If you are calling `pcidb` from a system that has an -alternate root mountpoint, you can either set the `PCIDB_CHROOT` environment -variable to that alternate path, or call the `pcidb.New()` function with the -`pcidb.WithChroot()` modifier. - -For example, if you are executing from within an application container that has -bind-mounted the root host filesystem to the mount point `/host`, you would set -`PCIDB_CHROOT` to `/host` so that pcidb can find files like -`/usr/share/misc/pci.ids` at `/host/usr/share/misc/pci.ids`. - -Alternately, you can use the `pcidb.WithChroot()` function like so: - -```go -pci := pcidb.New(pcidb.WithChroot("/host")) -``` - ### PCI device classes Let's take a look at the PCI device class information and how to query the PCI @@ -178,25 +169,11 @@ package main import ( "fmt" - "sort" + "slices" "github.com/jaypipes/pcidb" ) -type ByCountProducts []*pcidb.Vendor - -func (v ByCountProducts) Len() int { - return len(v) -} - -func (v ByCountProducts) Swap(i, j int) { - v[i], v[j] = v[j], v[i] -} - -func (v ByCountProducts) Less(i, j int) bool { - return len(v[i].Products) > len(v[j].Products) -} - func main() { pci, err := pcidb.New() if err != nil { @@ -210,7 +187,10 @@ func main() { x++ } - sort.Sort(ByCountProducts(vendors)) + slices.SortFunc(vendors, func(a, b *pcidb.Vendor) int { + return cmp.Compare(len(a.Products), len(b.Products)) + }) + slices.Reverse(vendors) fmt.Println("Top 5 vendors by product") fmt.Println("====================================================") @@ -220,16 +200,16 @@ func main() { } ``` -which yields (on my local workstation as of July 7th, 2018): +which yields (on my local workstation as of August 23rd, 2025): ``` Top 5 vendors by product ==================================================== -Intel Corporation ('8086') has 3389 products -NVIDIA Corporation ('10de') has 1358 products -Advanced Micro Devices, Inc. [AMD/ATI] ('1002') has 886 products -National Instruments ('1093') has 601 products -Chelsio Communications Inc ('1425') has 525 products +Intel Corporation ('8086') has 4461 products +NVIDIA Corporation ('10de') has 1853 products +Advanced Micro Devices, Inc. [AMD/ATI] ('1002') has 1115 products +Chelsio Communications Inc ('1425') has 669 products +National Instruments ('1093') has 609 products ``` The following is an example of querying the PCI product and subsystem @@ -324,81 +304,144 @@ func main() { } ``` -which yields (on my local workstation as of July 7th, 2018): +which yields (on my local workstation as of August 23rd, 2025): ``` Top 2 products by # different subvendors ==================================================== RTL-8100/8101L/8139 PCI Fast Ethernet Adapter ('8139') from Realtek Semiconductor Co., Ltd. -> 34 subsystems under the following different vendors: - - OVISLINK Corp. ('149c') - - EPoX Computer Co., Ltd. ('1695') - - Red Hat, Inc ('1af4') - - Mitac ('1071') - - Netgear ('1385') - - Micro-Star International Co., Ltd. [MSI] ('1462') - - Hangzhou Silan Microelectronics Co., Ltd. ('1904') - - Compex ('11f6') - - Edimax Computer Co. ('1432') - - KYE Systems Corporation ('1489') - - ZyXEL Communications Corporation ('187e') - - Acer Incorporated [ALI] ('1025') + - ASUSTeK Computer Inc. ('1043') - Matsushita Electric Industrial Co., Ltd. ('10f7') + - Compex ('11f6') + - Allied Telesis ('1259') + - Samsung Electronics Co Ltd ('144d') + - Micro-Star International Co., Ltd. [MSI] ('1462') - Ruby Tech Corp. ('146c') + - ZyXEL Communications Corporation ('187e') + - TTTech Computertechnik AG (Wrong ID) ('0357') + - Accton Technology Corporation ('1113') + - Billionton Systems Inc ('14cb') - Belkin ('1799') - - Allied Telesis ('1259') - - Unex Technology Corp. ('1429') - - CIS Technology Inc ('1436') - - D-Link System Inc ('1186') - - Ambicom Inc ('1395') + - Hangzhou Silan Microelectronics Co., Ltd. ('1904') - AOPEN Inc. ('a0a0') - - TTTech Computertechnik AG (Wrong ID) ('0357') - - Gigabyte Technology Co., Ltd ('1458') + - Acer Incorporated [ALI] ('1025') + - Surecom Technology ('10bd') + - D-Link System Inc ('1186') + - Hewlett-Packard Company ('103c') + - Mitac ('1071') + - Netgear ('1385') + - Edimax Computer Co. ('1432') - Packard Bell B.V. ('1631') - - Billionton Systems Inc ('14cb') - - Kingston Technologies ('2646') - - Accton Technology Corporation ('1113') - - Samsung Electronics Co Ltd ('144d') + - Gigabyte Technology Co., Ltd ('1458') + - KTI ('8e2e') + - CIS Technology Inc ('1436') + - Red Hat, Inc. ('1af4') + - Kingston Technology Company, Inc. ('2646') + - KYE Systems Corporation ('1489') + - Ambicom Inc ('1395') + - Unex Technology Corp. ('1429') + - OVISLINK Corp. ('149c') - Biostar Microtech Int'l Corp ('1565') + - EPoX Computer Co., Ltd. ('1695') - U.S. Robotics ('16ec') - - KTI ('8e2e') - - Hewlett-Packard Company ('103c') - - ASUSTeK Computer Inc. ('1043') - - Surecom Technology ('10bd') Bt878 Video Capture ('036e') from Brooktree Corporation - -> 30 subsystems under the following different vendors: - - iTuner ('aa00') - - Nebula Electronics Ltd. ('0071') - - DViCO Corporation ('18ac') - - iTuner ('aa05') - - iTuner ('aa0d') - - LeadTek Research Inc. ('107d') + -> 32 subsystems under the following different vendors: + - Hauppauge computer works Inc. ('0070') + - Askey Computer Corp. ('144f') - Avermedia Technologies Inc ('1461') - - Chaintech Computer Co. Ltd ('270f') - - iTuner ('aa07') - - iTuner ('aa0a') - - Microtune, Inc. ('1851') - - iTuner ('aa01') - - iTuner ('aa04') - - iTuner ('aa06') + - iTuner ('aa00') - iTuner ('aa0f') - - iTuner ('aa02') - - iTuner ('aa0b') - - Pinnacle Systems, Inc. (Wrong ID) ('bd11') - - Rockwell International ('127a') - - Askey Computer Corp. ('144f') + - Pinnacle Systems Inc. ('11bd') + - Euresys S.A. ('1805') - Twinhan Technology Co. Ltd ('1822') - - Anritsu Corp. ('1852') + - iTuner ('aa05') - iTuner ('aa08') - - Hauppauge computer works Inc. ('0070') - - Pinnacle Systems Inc. ('11bd') + - Nebula Electronics Ltd. ('0071') + - Chaintech Computer Co. Ltd ('270f') - Conexant Systems, Inc. ('14f1') - - iTuner ('aa09') + - iTuner ('aa01') - iTuner ('aa03') + - iTuner ('aa0b') + - iTuner ('aa0d') + - Microtune, Inc. ('1851') + - iTuner ('aa02') + - iTuner ('aa06') + - iTuner ('aa09') + - Anritsu Corp. ('1852') + - iTuner ('aa04') + - iTuner ('aa07') - iTuner ('aa0c') + - Pinnacle Systems, Inc. (Wrong ID) ('bd11') + - Unknown subvendor ('0000') + - Rockwell International ('127a') + - DViCO Corporation ('18ac') - iTuner ('aa0e') + - LeadTek Research Inc. ('107d') + - iTuner ('aa0a') ``` +## Discovery + +`pcidb` tries its best to automatically discover a `pci.ids` database file on +the local host. + +`pcidb`'s default behaviour is to first search for `pci.ids` DB files on the +local host system in well-known filesystem paths (Linux and MacOS): + +* `/usr/share/hwdata/pci.ids` +* `/usr/share/misc/pci.ids.gz` +* `/usr/share/hwdata/pci.ids` +* `/usr/share/misc/pci.ids.gz` + +> **NOTE**: Windows does not have a `pci.ids` database file installed by +> default. + +You can influence this discovery behaviour with the functions discussed in the +following sections. + +### Overriding the location of the `pci.ids` database file + +If you have a copy of a `pci.ids` database file in a non-standard location or +are working in an environment like Windows that does not have a `pci.ids` +database file installed by default and do not want `pcidb` to fetch an +up-to-date `pci.ids` database file over the network, you can tell `pcidb` +exactly where to find the `pci.ids` database using the `pcidb.WithPath()` +function, like so: + +```go +pci := pcidb.New(pcidb.WithPath("/path/to/pci.ids.gz")) +``` + +### Overriding the root mountpoint `pcidb` uses + +The default root mountpoint that `pcidb` uses when looking for information +about the host system is `/`. So, for example, when looking up known `pci.ids` +database files on Linux, `pcidb` will attempt to discover a `pci.ids` database +file at `/usr/share/misc/pci.ids`. If you are calling `pcidb` from a system +that has an alternate root mountpoint, you can either set the `PCIDB_CHROOT` +environment variable to that alternate path, or call the `pcidb.New()` function +with the `pcidb.WithChroot()` modifier. + +For example, if you are executing from within an application container that has +bind-mounted the root host filesystem to the mount point `/host`, you would set +`PCIDB_CHROOT` to `/host` so that pcidb can find files like +`/usr/share/misc/pci.ids` at `/host/usr/share/misc/pci.ids`. + +Alternately, you can use the `pcidb.WithChroot()` function like so: + +```go +pci := pcidb.New(pcidb.WithChroot("/host")) +``` + +### Fetching `pci.ids` database file over the network + +If `pcidb` cannot find a `pci.ids` DB file on the local host system, you can +configure `pcidb` to fetch a current `pci.ids` DB file from the network. You +can enable this network-fetching behaviour with the +`pcidb.WithEnableNetworkFetch()` function or set the +`PCIDB_ENABLE_NETWORK_FETCH` environs variable to a non-0 value. + ## Developers Contributions to `pcidb` are welcomed! Fork the repo on GitHub and submit a pull @@ -409,7 +452,6 @@ request or bug report. You can run unit tests easily using the `make test` command, like so: - ``` [jaypipes@uberbox pcidb]$ make test go test github.com/jaypipes/pcidb diff --git a/vendor/github.com/jaypipes/pcidb/context.go b/vendor/github.com/jaypipes/pcidb/context.go deleted file mode 100644 index da3459965..000000000 --- a/vendor/github.com/jaypipes/pcidb/context.go +++ /dev/null @@ -1,86 +0,0 @@ -package pcidb - -import ( - "fmt" - "os" - "path/filepath" - "runtime" - - homedir "github.com/mitchellh/go-homedir" -) - -// Concrete merged set of configuration switches that get passed to pcidb -// internal functions -type context struct { - chroot string - cacheOnly bool - cachePath string - path string - enableNetworkFetch bool - searchPaths []string -} - -func contextFromOptions(merged *WithOption) *context { - ctx := &context{ - chroot: *merged.Chroot, - cacheOnly: *merged.CacheOnly, - cachePath: getCachePath(), - enableNetworkFetch: *merged.EnableNetworkFetch, - path: *merged.Path, - searchPaths: make([]string, 0), - } - ctx.setSearchPaths() - return ctx -} - -func getCachePath() string { - hdir, err := homedir.Dir() - if err != nil { - fmt.Fprintf(os.Stderr, "Failed getting homedir.Dir(): %v", err) - return "" - } - fp, err := homedir.Expand(filepath.Join(hdir, ".cache", "pci.ids")) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed expanding local cache path: %v", err) - return "" - } - return fp -} - -// Depending on the operating system, sets the context's searchPaths to a set -// of local filepaths to search for a pci.ids database file -func (ctx *context) setSearchPaths() { - // Look in direct path first, if set - if ctx.path != "" { - ctx.searchPaths = append(ctx.searchPaths, ctx.path) - return - } - // A set of filepaths we will first try to search for the pci-ids DB file - // on the local machine. If we fail to find one, we'll try pulling the - // latest pci-ids file from the network - ctx.searchPaths = append(ctx.searchPaths, ctx.cachePath) - if ctx.cacheOnly { - return - } - - rootPath := ctx.chroot - - if runtime.GOOS != "windows" { - ctx.searchPaths = append( - ctx.searchPaths, - filepath.Join(rootPath, "usr", "share", "hwdata", "pci.ids"), - ) - ctx.searchPaths = append( - ctx.searchPaths, - filepath.Join(rootPath, "usr", "share", "misc", "pci.ids"), - ) - ctx.searchPaths = append( - ctx.searchPaths, - filepath.Join(rootPath, "usr", "share", "hwdata", "pci.ids.gz"), - ) - ctx.searchPaths = append( - ctx.searchPaths, - filepath.Join(rootPath, "usr", "share", "misc", "pci.ids.gz"), - ) - } -} diff --git a/vendor/github.com/jaypipes/pcidb/discover.go b/vendor/github.com/jaypipes/pcidb/discover.go deleted file mode 100644 index b0452d7db..000000000 --- a/vendor/github.com/jaypipes/pcidb/discover.go +++ /dev/null @@ -1,111 +0,0 @@ -// -// 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 ( - "bufio" - "compress/gzip" - "io" - "net/http" - "os" - "path/filepath" - "strings" -) - -const ( - PCIIDS_URI = "https://pci-ids.ucw.cz/v2.2/pci.ids.gz" - USER_AGENT = "golang-jaypipes-pcidb" -) - -func (db *PCIDB) load(ctx *context) error { - var foundPath string - for _, fp := range ctx.searchPaths { - if _, err := os.Stat(fp); err == nil { - foundPath = fp - break - } - } - if foundPath == "" { - if !ctx.enableNetworkFetch { - return ERR_NO_DB - } - // OK, so we didn't find any host-local copy of the pci-ids DB file. Let's - // try fetching it from the network and storing it - if err := cacheDBFile(ctx.cachePath); err != nil { - return err - } - foundPath = ctx.cachePath - } - f, err := os.Open(foundPath) - if err != nil { - return err - } - defer f.Close() - - var scanner *bufio.Scanner - if strings.HasSuffix(foundPath, ".gz") { - var zipReader *gzip.Reader - if zipReader, err = gzip.NewReader(f); err != nil { - return err - } - defer zipReader.Close() - scanner = bufio.NewScanner(zipReader) - } else { - scanner = bufio.NewScanner(f) - } - - return parseDBFile(db, scanner) -} - -func ensureDir(fp string) error { - fpDir := filepath.Dir(fp) - if _, err := os.Stat(fpDir); os.IsNotExist(err) { - err = os.MkdirAll(fpDir, os.ModePerm) - if err != nil { - return err - } - } - return nil -} - -// Pulls down the latest copy of the pci-ids file from the network and stores -// it in the local host filesystem -func cacheDBFile(cacheFilePath string) error { - ensureDir(cacheFilePath) - - client := new(http.Client) - request, err := http.NewRequest("GET", PCIIDS_URI, nil) - if err != nil { - return err - } - request.Header.Set("User-Agent", USER_AGENT) - response, err := client.Do(request) - if err != nil { - return err - } - defer response.Body.Close() - f, err := os.Create(cacheFilePath) - if err != nil { - return err - } - defer func() { - if err != nil { - os.Remove(cacheFilePath) - } - }() - defer f.Close() - // write the gunzipped contents to our local cache file - zr, err := gzip.NewReader(response.Body) - if err != nil { - return err - } - defer zr.Close() - if _, err = io.Copy(f, zr); err != nil { - return err - } - return err -} diff --git a/vendor/github.com/jaypipes/pcidb/internal/discover.go b/vendor/github.com/jaypipes/pcidb/internal/discover.go new file mode 100644 index 000000000..43d75e2b6 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/internal/discover.go @@ -0,0 +1,168 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package internal + +import ( + "compress/gzip" + "io" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + + "github.com/jaypipes/pcidb/types" +) + +const ( + pciidsURI = "https://pci-ids.ucw.cz/v2.2/pci.ids.gz" + userAgent = "golang-jaypipes-pcidb" +) + +// Discover returns an io.Reader for an opened PCIIDS database file or gzipped +// database file. It examines the supplied context/options and determines where +// to find a PCIIDS database file, from a cached location, a supplied path +// override, one of a set of well-known filesystem locations (on Linux) or even +// fetching the canonical PCIIDS database file from the network (as a last +// resort and only when network fetching has been enabled with the +// PCIDB_ENABLE_NETWORK_FETCH=1 environment variable) +func Discover(opts *types.WithOption) (io.ReadCloser, error) { + var foundPath string + for _, fp := range searchPaths(opts) { + if _, err := os.Stat(fp); err == nil { + foundPath = fp + break + } + } + + if foundPath == "" { + if opts.EnableNetworkFetch != nil && !*opts.EnableNetworkFetch { + return nil, types.ErrNoDB + } + var cachePath = types.DefaultCachePath + if opts.CachePath != nil && *opts.CachePath != "" { + cachePath = *opts.CachePath + } + if cachePath == "" { + return nil, types.ErrNoPaths + } + // OK, so we didn't find any host-local copy of the pci-ids DB file. Let's + // try fetching it from the network and storing it + if err := cacheDBFile(cachePath); err != nil { + return nil, err + } + foundPath = cachePath + } + f, err := os.Open(foundPath) + if err != nil { + return nil, err + } + + if strings.HasSuffix(foundPath, ".gz") { + var zipReader *gzip.Reader + if zipReader, err = gzip.NewReader(f); err != nil { + return nil, err + } + return zipReader, nil + } + return f, nil +} + +// Depending on the operating system, sets the context's searchPaths to a set +// of local filepaths to search for a pci.ids database file +func searchPaths(opts *types.WithOption) []string { + // Look in direct path first, if set + if opts.Path != nil && *opts.Path != "" { + return []string{*opts.Path} + } + paths := []string{} + // A set of filepaths we will first try to search for the pci-ids DB file + // on the local machine. If we fail to find one, we'll try pulling the + // latest pci-ids file from the network + cachePath := types.DefaultCachePath + if opts.CachePath != nil { + cachePath = *opts.CachePath + } + paths = append(paths, cachePath) + if opts.CacheOnly != nil && *opts.CacheOnly { + return paths + } + + rootPath := types.DefaultChroot + if opts.Chroot != nil && *opts.Chroot != "" { + rootPath = *opts.Chroot + } + + if runtime.GOOS != "windows" { + paths = append( + paths, + filepath.Join(rootPath, "usr", "share", "hwdata", "pci.ids"), + ) + paths = append( + paths, + filepath.Join(rootPath, "usr", "share", "misc", "pci.ids"), + ) + paths = append( + paths, + filepath.Join(rootPath, "usr", "share", "hwdata", "pci.ids.gz"), + ) + paths = append( + paths, + filepath.Join(rootPath, "usr", "share", "misc", "pci.ids.gz"), + ) + } + return paths +} + +func ensureDir(fp string) error { + fpDir := filepath.Dir(fp) + if _, err := os.Stat(fpDir); os.IsNotExist(err) { + err = os.MkdirAll(fpDir, os.ModePerm) + if err != nil { + return err + } + } + return nil +} + +// Pulls down the latest copy of the pci-ids file from the network and stores +// it in the local host filesystem +func cacheDBFile(cacheFilePath string) error { + ensureDir(cacheFilePath) + + client := new(http.Client) + request, err := http.NewRequest("GET", pciidsURI, nil) + if err != nil { + return err + } + request.Header.Set("User-Agent", userAgent) + response, err := client.Do(request) + if err != nil { + return err + } + defer response.Body.Close() + f, err := os.Create(cacheFilePath) + if err != nil { + return err + } + defer func() { + if err != nil { + os.Remove(cacheFilePath) + } + }() + defer f.Close() + // write the gunzipped contents to our local cache file + zr, err := gzip.NewReader(response.Body) + if err != nil { + return err + } + defer zr.Close() + if _, err = io.Copy(f, zr); err != nil { + return err + } + return err +} diff --git a/vendor/github.com/jaypipes/pcidb/internal/option.go b/vendor/github.com/jaypipes/pcidb/internal/option.go new file mode 100644 index 000000000..05674d21f --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/internal/option.go @@ -0,0 +1,82 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package internal + +import ( + "fmt" + "os" + "strconv" + + "github.com/jaypipes/pcidb/types" +) + +func MergeOptions(opts ...*types.WithOption) *types.WithOption { + // Grab options from the environs by default + chroot := types.DefaultChroot + if val, exists := os.LookupEnv(types.EnvVarChroot); exists { + chroot = val + } + path := "" + if val, exists := os.LookupEnv(types.EnvVarPath); exists { + path = val + } + cacheOnly := types.DefaultCacheOnly + if val, exists := os.LookupEnv(types.EnvVarCacheOnly); exists { + if parsed, err := strconv.ParseBool(val); err != nil { + fmt.Fprintf( + os.Stderr, + "Failed parsing a bool from %s "+ + "environ value of %s", + types.EnvVarCacheOnly, val, + ) + } else if parsed { + cacheOnly = parsed + } + } + enableNetworkFetch := types.DefaultEnableNetworkFetch + if val, exists := os.LookupEnv(types.EnvVarEnableNetworkFetch); exists { + if parsed, err := strconv.ParseBool(val); err != nil { + fmt.Fprintf( + os.Stderr, + "Failed parsing a bool from %s environ value of %s", + types.EnvVarEnableNetworkFetch, val, + ) + } else if parsed { + enableNetworkFetch = parsed + } + } + + merged := &types.WithOption{} + for _, opt := range opts { + if opt.Chroot != nil { + merged.Chroot = opt.Chroot + } + if opt.CacheOnly != nil { + merged.CacheOnly = opt.CacheOnly + } + if opt.EnableNetworkFetch != nil { + merged.EnableNetworkFetch = opt.EnableNetworkFetch + } + if opt.Path != nil { + merged.Path = opt.Path + } + } + // Set the default value if missing from merged + if merged.Chroot == nil { + merged.Chroot = &chroot + } + if merged.CacheOnly == nil { + merged.CacheOnly = &cacheOnly + } + if merged.EnableNetworkFetch == nil { + merged.EnableNetworkFetch = &enableNetworkFetch + } + if merged.Path == nil { + merged.Path = &path + } + return merged +} diff --git a/vendor/github.com/jaypipes/pcidb/parse.go b/vendor/github.com/jaypipes/pcidb/internal/parse.go similarity index 72% rename from vendor/github.com/jaypipes/pcidb/parse.go rename to vendor/github.com/jaypipes/pcidb/internal/parse.go index 0fee5fe5e..02d302ea1 100644 --- a/vendor/github.com/jaypipes/pcidb/parse.go +++ b/vendor/github.com/jaypipes/pcidb/internal/parse.go @@ -4,28 +4,38 @@ // See the COPYING file in the root project directory for full text. // -package pcidb +package internal import ( "bufio" + "io" "strings" + + "github.com/jaypipes/pcidb/types" ) -func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { +// FromReader reads the supplied io.ReadCloser representing a PCIIDS database +// file or gzipped database file and returns a populated pcidb.DB with parsed +// PCI product, vendor and class information. +func FromReader( + f io.ReadCloser, +) *types.DB { + defer f.Close() + scanner := bufio.NewScanner(f) inClassBlock := false - db.Classes = make(map[string]*Class, 20) - db.Vendors = make(map[string]*Vendor, 200) - db.Products = make(map[string]*Product, 1000) - subclasses := make([]*Subclass, 0) - progIfaces := make([]*ProgrammingInterface, 0) - var curClass *Class - var curSubclass *Subclass - var curProgIface *ProgrammingInterface - vendorProducts := make([]*Product, 0) - var curVendor *Vendor - var curProduct *Product - var curSubsystem *Product - productSubsystems := make([]*Product, 0) + classes := make(map[string]*types.Class, 20) + vendors := make(map[string]*types.Vendor, 200) + products := make(map[string]*types.Product, 1000) + subclasses := make([]*types.Subclass, 0) + progIfaces := make([]*types.ProgrammingInterface, 0) + var curClass *types.Class + var curSubclass *types.Subclass + var curProgIface *types.ProgrammingInterface + vendorProducts := make([]*types.Product, 0) + var curVendor *types.Vendor + var curProduct *types.Product + var curSubsystem *types.Product + productSubsystems := make([]*types.Product, 0) for scanner.Scan() { line := scanner.Text() // skip comments and blank lines @@ -42,17 +52,17 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { if curClass != nil { // finalize existing class because we found a new class block curClass.Subclasses = subclasses - subclasses = make([]*Subclass, 0) + subclasses = make([]*types.Subclass, 0) } inClassBlock = true classID := string(lineBytes[2:4]) className := string(lineBytes[6:]) - curClass = &Class{ + curClass = &types.Class{ ID: classID, Name: className, Subclasses: subclasses, } - db.Classes[curClass.ID] = curClass + classes[curClass.ID] = curClass continue } @@ -65,17 +75,17 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { if curVendor != nil { // finalize existing vendor because we found a new vendor block curVendor.Products = vendorProducts - vendorProducts = make([]*Product, 0) + vendorProducts = make([]*types.Product, 0) } inClassBlock = false vendorID := string(lineBytes[0:4]) vendorName := string(lineBytes[6:]) - curVendor = &Vendor{ + curVendor = &types.Vendor{ ID: vendorID, Name: vendorName, Products: vendorProducts, } - db.Vendors[curVendor.ID] = curVendor + vendors[curVendor.ID] = curVendor continue } @@ -97,11 +107,11 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { if curSubclass != nil { // finalize existing subclass because we found a new subclass block curSubclass.ProgrammingInterfaces = progIfaces - progIfaces = make([]*ProgrammingInterface, 0) + progIfaces = make([]*types.ProgrammingInterface, 0) } subclassID := string(lineBytes[1:3]) subclassName := string(lineBytes[5:]) - curSubclass = &Subclass{ + curSubclass = &types.Subclass{ ID: subclassID, Name: subclassName, ProgrammingInterfaces: progIfaces, @@ -111,18 +121,18 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { if curProduct != nil { // finalize existing product because we found a new product block curProduct.Subsystems = productSubsystems - productSubsystems = make([]*Product, 0) + productSubsystems = make([]*types.Product, 0) } productID := string(lineBytes[1:5]) productName := string(lineBytes[7:]) productKey := curVendor.ID + productID - curProduct = &Product{ + curProduct = &types.Product{ VendorID: curVendor.ID, ID: productID, Name: productName, } vendorProducts = append(vendorProducts, curProduct) - db.Products[productKey] = curProduct + products[productKey] = curProduct } } else { // Lines beginning with two TAB characters are *either* a subsystem @@ -141,7 +151,7 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { if inClassBlock { progIfaceID := string(lineBytes[2:4]) progIfaceName := string(lineBytes[6:]) - curProgIface = &ProgrammingInterface{ + curProgIface = &types.ProgrammingInterface{ ID: progIfaceID, Name: progIfaceName, } @@ -150,7 +160,7 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { vendorID := string(lineBytes[2:6]) subsystemID := string(lineBytes[7:11]) subsystemName := string(lineBytes[13:]) - curSubsystem = &Product{ + curSubsystem = &types.Product{ VendorID: vendorID, ID: subsystemID, Name: subsystemName, @@ -159,5 +169,9 @@ func parseDBFile(db *PCIDB, scanner *bufio.Scanner) error { } } } - return nil + return &types.DB{ + Classes: classes, + Products: products, + Vendors: vendors, + } } diff --git a/vendor/github.com/jaypipes/pcidb/main.go b/vendor/github.com/jaypipes/pcidb/main.go deleted file mode 100644 index d518748e7..000000000 --- a/vendor/github.com/jaypipes/pcidb/main.go +++ /dev/null @@ -1,196 +0,0 @@ -// -// 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 - // Enables fetching a pci-ids from a known location on the network if no - // local pci-ids DB files can be found. - EnableNetworkFetch *bool - // Path points to the absolute path of a pci.ids file in a non-standard - // location. - Path *string -} - -func WithChroot(dir string) *WithOption { - return &WithOption{Chroot: &dir} -} - -func WithCacheOnly() *WithOption { - return &WithOption{CacheOnly: &trueVar} -} - -func WithDirectPath(path string) *WithOption { - return &WithOption{Path: &path} -} - -func WithEnableNetworkFetch() *WithOption { - return &WithOption{EnableNetworkFetch: &trueVar} -} - -func mergeOptions(opts ...*WithOption) *WithOption { - // Grab options from the environs by default - defaultChroot := "/" - if val, exists := os.LookupEnv("PCIDB_CHROOT"); exists { - defaultChroot = val - } - path := "" - if val, exists := os.LookupEnv("PCIDB_PATH"); exists { - path = 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 - } - } - defaultEnableNetworkFetch := false - if val, exists := os.LookupEnv("PCIDB_ENABLE_NETWORK_FETCH"); exists { - if parsed, err := strconv.ParseBool(val); err != nil { - fmt.Fprintf( - os.Stderr, - "Failed parsing a bool from PCIDB_ENABLE_NETWORK_FETCH "+ - "environ value of %s", - val, - ) - } else if parsed { - defaultEnableNetworkFetch = 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.EnableNetworkFetch != nil { - merged.EnableNetworkFetch = opt.EnableNetworkFetch - } - if opt.Path != nil { - merged.Path = opt.Path - } - } - // Set the default value if missing from merged - if merged.Chroot == nil { - merged.Chroot = &defaultChroot - } - if merged.CacheOnly == nil { - merged.CacheOnly = &defaultCacheOnly - } - if merged.EnableNetworkFetch == nil { - merged.EnableNetworkFetch = &defaultEnableNetworkFetch - } - if merged.Path == nil { - merged.Path = &path - } - 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 -} diff --git a/vendor/github.com/jaypipes/pcidb/pcidb.go b/vendor/github.com/jaypipes/pcidb/pcidb.go new file mode 100644 index 000000000..bd185aaba --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/pcidb.go @@ -0,0 +1,66 @@ +// +// 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 ( + "github.com/jaypipes/pcidb/internal" + "github.com/jaypipes/pcidb/types" +) + +type DB = types.DB +type Product = types.Product +type Vendor = types.Vendor +type Class = types.Class +type Subclass = types.Subclass +type ProgrammingInterface = types.ProgrammingInterface +type WithOption = types.WithOption + +// WithChroot overrides the root directory used for discovery of pci-ids +// database files. +var WithChroot = types.WithChroot + +// WithCachePath overrides the directory that pcidb uses to look up +// pre-found/pre-fetching pci.ids database files. +var WithCachePath = types.WithCachePath + +// WithCacheOnly disables lookup of pci.ids database files over the network and +// forces pcidb to only use any pre-cached pci.ids database files in its cache +// directory. +var WithCacheOnly = types.WithCacheOnly + +// WithPath overrides the pci.ids database file discovery and points pcidb at a +// known location of a pci.ids or pci.ids.gz database file. +var WithPath = types.WithPath + +// DEPRECATED. Here for backwards-compat +var WithDirectPath = WithPath + +// WithEnableNetworkFetch enables the fetching of pci.ids database files over +// the Internet if a pci.ids database file cannot be found on the host +// filesystem or the pcidb cache directory. +var WithEnableNetworkFetch = types.WithEnableNetworkFetch + +// Backward-compat, please refer to the pcidb types.DB type definition +type PCIDB = types.DB + +// New returns a pointer to a pcidb.DB 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 ...*types.WithOption) (*types.DB, error) { + merged := internal.MergeOptions(opts...) + f, err := internal.Discover(merged) + if err != nil { + return nil, err + } + return internal.FromReader(f), nil +} diff --git a/vendor/github.com/jaypipes/pcidb/types/class.go b/vendor/github.com/jaypipes/pcidb/types/class.go new file mode 100644 index 000000000..4fd95c5f3 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/class.go @@ -0,0 +1,17 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +// Class is the PCI class +type Class struct { + // ID is the hex-encoded PCI_ID for the device class + ID string `json:"id"` + // Name is the common string name for the class + Name string `json:"name"` + // Subclasses are any subclasses belonging to this class + Subclasses []*Subclass `json:"subclasses"` +} diff --git a/vendor/github.com/jaypipes/pcidb/types/db.go b/vendor/github.com/jaypipes/pcidb/types/db.go new file mode 100644 index 000000000..61d95b837 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/db.go @@ -0,0 +1,17 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +type DB struct { + // Classes is a map, keyed by class ID, of PCI Class information + Classes map[string]*Class `json:"classes"` + // Vendors is a map, keyed by vendor ID, of PCI Vendor information + Vendors map[string]*Vendor `json:"vendors"` + // Products is a map, keyed by vendor ID + product ID, of PCI product + // information + Products map[string]*Product `json:"products"` +} diff --git a/vendor/github.com/jaypipes/pcidb/types/default.go b/vendor/github.com/jaypipes/pcidb/types/default.go new file mode 100644 index 000000000..85e6e3d20 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/default.go @@ -0,0 +1,35 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +import ( + "os" + "path/filepath" +) + +const ( + DefaultChroot = "/" + DefaultCacheOnly = false + DefaultEnableNetworkFetch = false +) + +var ( + DefaultCachePath = getCachePath() +) + +func getCachePath() string { + hdir, err := os.UserHomeDir() + if err != nil { + // os.UserHomeDir() returns an error when $HOME isn't set on Linux. + // This is the only error os.UserHomeDir() returns, and we don't care + // about it, so just ignore the error. + // + // https://github.com/jaypipes/pcidb/issues/38 + return "" + } + return filepath.Join(hdir, ".cache", "pci.ids") +} diff --git a/vendor/github.com/jaypipes/pcidb/types/env.go b/vendor/github.com/jaypipes/pcidb/types/env.go new file mode 100644 index 000000000..8ff5151f5 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/env.go @@ -0,0 +1,15 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +const ( + EnvVarChroot = "PCIDB_CHROOT" + EnvVarPath = "PCIDB_PATH" + EnvVarCacheOnly = "PCIDB_CACHE_ONLY" + EnvVarCachePath = "PCIDB_CACHE_PATH" + EnvVarEnableNetworkFetch = "PCIDB_ENABLE_NETWORK_FETCH" +) diff --git a/vendor/github.com/jaypipes/pcidb/types/error.go b/vendor/github.com/jaypipes/pcidb/types/error.go new file mode 100644 index 000000000..dede4ee1e --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/error.go @@ -0,0 +1,20 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +import "errors" + +var ( + ErrNoDB = errors.New( + "pcidb: No pci-ids DB files found (and network fetch disabled)", + ) + ErrNoPaths = errors.New( + "pcidb: no search paths and cache path is empty.", + ) + // Backwards-compat, deprecated, please reference ErrNoDB + ERR_NO_DB = ErrNoDB +) diff --git a/vendor/github.com/jaypipes/pcidb/types/option.go b/vendor/github.com/jaypipes/pcidb/types/option.go new file mode 100644 index 000000000..05eeedd99 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/option.go @@ -0,0 +1,66 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +var ( + trueVar = true +) + +// 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 + // CachePath overrides the pcidb cache path, which defaults to + // $HOME/.cache/pci.ids + CachePath *string + // Enables fetching a pci-ids from a known location on the network if no + // local pci-ids DB files can be found. + EnableNetworkFetch *bool + // Path points to the absolute path of a pci.ids file in a non-standard + // location. + Path *string +} + +// WithChroot overrides the root directory used for discovery of pci-ids +// database files. +func WithChroot(dir string) *WithOption { + return &WithOption{Chroot: &dir} +} + +// WithCachePath overrides the directory that pcidb uses to look up +// pre-found/pre-fetching pci.ids database files. +func WithCachePath(path string) *WithOption { + return &WithOption{CachePath: &path} +} + +// WithCacheOnly disables lookup of pci.ids database files over the network and +// forces pcidb to only use any pre-cached pci.ids database files in its cache +// directory. +func WithCacheOnly() *WithOption { + return &WithOption{CacheOnly: &trueVar} +} + +// WithPath overrides the pci.ids database file discovery and points pcidb at a +// known location of a pci.ids or pci.ids.gz database file. +func WithPath(path string) *WithOption { + return &WithOption{Path: &path} +} + +// Backwards-compat +var WithDirectPath = WithPath + +// WithEnableNetworkFetch enables the fetching of pci.ids database files over +// the Internet if a pci.ids database file cannot be found on the host +// filesystem or the pcidb cache directory. +func WithEnableNetworkFetch() *WithOption { + return &WithOption{EnableNetworkFetch: &trueVar} +} diff --git a/vendor/github.com/jaypipes/pcidb/types/product.go b/vendor/github.com/jaypipes/pcidb/types/product.go new file mode 100644 index 000000000..6b1715b00 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/product.go @@ -0,0 +1,22 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +// Product provides information about a PCI device model. +// +// In the hardware world, the PCI "device_id" is the identifier for the +// product/model +type Product struct { + // VendorID is the vendor ID for the product + VendorID string `json:"vendor_id"` + // ID is the hex-encoded PCI_ID for the product/model + ID string `json:"id"` + // Name is the common string name of the vendor + Name string `json:"name"` + // Subsystems contains "subdevices" or "subsystems" for the product + Subsystems []*Product `json:"subsystems"` +} diff --git a/vendor/github.com/jaypipes/pcidb/types/programming_interface.go b/vendor/github.com/jaypipes/pcidb/types/programming_interface.go new file mode 100644 index 000000000..f5d09da86 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/programming_interface.go @@ -0,0 +1,16 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +// ProgrammingInterface is the PCI programming interface for a class of PCI +// devices +type ProgrammingInterface struct { + // IS is the hex-encoded PCI_ID of the programming interface + ID string `json:"id"` + // Name is the common string name for the programming interface + Name string `json:"name"` +} diff --git a/vendor/github.com/jaypipes/pcidb/types/subclass.go b/vendor/github.com/jaypipes/pcidb/types/subclass.go new file mode 100644 index 000000000..2d2309672 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/subclass.go @@ -0,0 +1,18 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +// Subclass is a subdivision of a PCI class +type Subclass struct { + // ID is the hex-encoded PCI_ID for the device subclass + ID string `json:"id"` + // Name is the common string name for the subclass + Name string `json:"name"` + // ProgrammingInterfaces contains any programming interfaces this subclass + // might have + ProgrammingInterfaces []*ProgrammingInterface `json:"programming_interfaces"` +} diff --git a/vendor/github.com/jaypipes/pcidb/types/vendor.go b/vendor/github.com/jaypipes/pcidb/types/vendor.go new file mode 100644 index 000000000..6eb361081 --- /dev/null +++ b/vendor/github.com/jaypipes/pcidb/types/vendor.go @@ -0,0 +1,17 @@ +// +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package types + +// Vendor provides information about a device vendor +type Vendor struct { + // IS is the hex-encoded PCI_ID for the vendor + ID string `json:"id"` + // Name is the common string name of the vendor + Name string `json:"name"` + // Products contains all top-level devices for the vendor + Products []*Product `json:"products"` +} diff --git a/vendor/github.com/mitchellh/go-homedir/LICENSE b/vendor/github.com/mitchellh/go-homedir/LICENSE deleted file mode 100644 index f9c841a51..000000000 --- a/vendor/github.com/mitchellh/go-homedir/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013 Mitchell Hashimoto - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/vendor/github.com/mitchellh/go-homedir/README.md b/vendor/github.com/mitchellh/go-homedir/README.md deleted file mode 100644 index d70706d5b..000000000 --- a/vendor/github.com/mitchellh/go-homedir/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# go-homedir - -This is a Go library for detecting the user's home directory without -the use of cgo, so the library can be used in cross-compilation environments. - -Usage is incredibly simple, just call `homedir.Dir()` to get the home directory -for a user, and `homedir.Expand()` to expand the `~` in a path to the home -directory. - -**Why not just use `os/user`?** The built-in `os/user` package requires -cgo on Darwin systems. This means that any Go code that uses that package -cannot cross compile. But 99% of the time the use for `os/user` is just to -retrieve the home directory, which we can do for the current user without -cgo. This library does that, enabling cross-compilation. diff --git a/vendor/github.com/mitchellh/go-homedir/homedir.go b/vendor/github.com/mitchellh/go-homedir/homedir.go deleted file mode 100644 index 25378537e..000000000 --- a/vendor/github.com/mitchellh/go-homedir/homedir.go +++ /dev/null @@ -1,167 +0,0 @@ -package homedir - -import ( - "bytes" - "errors" - "os" - "os/exec" - "path/filepath" - "runtime" - "strconv" - "strings" - "sync" -) - -// DisableCache will disable caching of the home directory. Caching is enabled -// by default. -var DisableCache bool - -var homedirCache string -var cacheLock sync.RWMutex - -// Dir returns the home directory for the executing user. -// -// This uses an OS-specific method for discovering the home directory. -// An error is returned if a home directory cannot be detected. -func Dir() (string, error) { - if !DisableCache { - cacheLock.RLock() - cached := homedirCache - cacheLock.RUnlock() - if cached != "" { - return cached, nil - } - } - - cacheLock.Lock() - defer cacheLock.Unlock() - - var result string - var err error - if runtime.GOOS == "windows" { - result, err = dirWindows() - } else { - // Unix-like system, so just assume Unix - result, err = dirUnix() - } - - if err != nil { - return "", err - } - homedirCache = result - return result, nil -} - -// Expand expands the path to include the home directory if the path -// is prefixed with `~`. If it isn't prefixed with `~`, the path is -// returned as-is. -func Expand(path string) (string, error) { - if len(path) == 0 { - return path, nil - } - - if path[0] != '~' { - return path, nil - } - - if len(path) > 1 && path[1] != '/' && path[1] != '\\' { - return "", errors.New("cannot expand user-specific home dir") - } - - dir, err := Dir() - if err != nil { - return "", err - } - - return filepath.Join(dir, path[1:]), nil -} - -// Reset clears the cache, forcing the next call to Dir to re-detect -// the home directory. This generally never has to be called, but can be -// useful in tests if you're modifying the home directory via the HOME -// env var or something. -func Reset() { - cacheLock.Lock() - defer cacheLock.Unlock() - homedirCache = "" -} - -func dirUnix() (string, error) { - homeEnv := "HOME" - if runtime.GOOS == "plan9" { - // On plan9, env vars are lowercase. - homeEnv = "home" - } - - // First prefer the HOME environmental variable - if home := os.Getenv(homeEnv); home != "" { - return home, nil - } - - var stdout bytes.Buffer - - // If that fails, try OS specific commands - if runtime.GOOS == "darwin" { - cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`) - cmd.Stdout = &stdout - if err := cmd.Run(); err == nil { - result := strings.TrimSpace(stdout.String()) - if result != "" { - return result, nil - } - } - } else { - cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid())) - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - // If the error is ErrNotFound, we ignore it. Otherwise, return it. - if err != exec.ErrNotFound { - return "", err - } - } else { - if passwd := strings.TrimSpace(stdout.String()); passwd != "" { - // username:password:uid:gid:gecos:home:shell - passwdParts := strings.SplitN(passwd, ":", 7) - if len(passwdParts) > 5 { - return passwdParts[5], nil - } - } - } - } - - // If all else fails, try the shell - stdout.Reset() - cmd := exec.Command("sh", "-c", "cd && pwd") - cmd.Stdout = &stdout - if err := cmd.Run(); err != nil { - return "", err - } - - result := strings.TrimSpace(stdout.String()) - if result == "" { - return "", errors.New("blank output when reading home directory") - } - - return result, nil -} - -func dirWindows() (string, error) { - // First prefer the HOME environmental variable - if home := os.Getenv("HOME"); home != "" { - return home, nil - } - - // Prefer standard environment variable USERPROFILE - if home := os.Getenv("USERPROFILE"); home != "" { - return home, nil - } - - drive := os.Getenv("HOMEDRIVE") - path := os.Getenv("HOMEPATH") - home := drive + path - if drive == "" || path == "" { - return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank") - } - - return home, nil -} diff --git a/vendor/github.com/yusufpapurcu/wmi/wmi.go b/vendor/github.com/yusufpapurcu/wmi/wmi.go index 26c3581c9..03f386ed5 100644 --- a/vendor/github.com/yusufpapurcu/wmi/wmi.go +++ b/vendor/github.com/yusufpapurcu/wmi/wmi.go @@ -456,6 +456,18 @@ func (c *Client) loadEntity(dst interface{}, src *ole.IDispatch) (errFieldMismat Reason: "not a Float32", } } + case float64: + switch f.Kind() { + case reflect.Float32, reflect.Float64: + f.SetFloat(val) + default: + return &ErrFieldMismatch{ + StructType: of.Type(), + FieldName: n, + Reason: "not a Float64", + } + } + default: if f.Kind() == reflect.Slice { switch f.Type().Elem().Kind() { diff --git a/vendor/howett.net/plist/bplist_parser.go b/vendor/howett.net/plist/bplist_parser.go index 1825b570b..8bb164e1d 100644 --- a/vendor/howett.net/plist/bplist_parser.go +++ b/vendor/howett.net/plist/bplist_parser.go @@ -137,7 +137,10 @@ func (p *bplistParser) parseSizedInteger(off offset, nbytes int) (lo uint64, hi case 16: lo, hi = binary.BigEndian.Uint64(p.buffer[off+8:]), binary.BigEndian.Uint64(p.buffer[off:]) default: - panic(errors.New("illegal integer size")) + if nbytes > 8 { + panic(errors.New("illegal integer size")) + } + lo, hi = binary.BigEndian.Uint64(p.buffer[off-(8-offset(nbytes)):]) & ((1< 0 { t := v.Type() @@ -168,3 +200,22 @@ func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { } return v } + +// valueForWriting returns v's field value corresponding to finfo. +// It's equivalent to v.FieldByIndex(finfo.idx), but bails out if one of the +// indices indicated that it should be omitted if it's empty and it is empty. +func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { + for i, x := range finfo.idx { + t := v.Type() + if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { + v = v.Elem() + } + + v = v.Field(x) + + if (finfo.omitEmptyDepthMap&(1<= val.Cap() { - ncap := 2 * cnt - if ncap < 4 { - ncap = 4 + if cnt > val.Cap() { + ncap := val.Cap() + for ncap < cnt { + ncap = growSliceCap(ncap) } new := reflect.MakeSlice(val.Type(), val.Len(), ncap) reflect.Copy(new, val) @@ -241,7 +242,16 @@ func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) { p.unmarshal(sval, val.Index(n)) n++ } - return +} + +func growSliceCap(cap int) int { + if cap == 0 { + return 4 + } else if cap < 1024 { + return cap * 2 // Double for small slices + } else { + return cap + cap/4 // Increase by 25% for large slices + } } func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) { @@ -260,13 +270,19 @@ func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) { } for _, finfo := range tinfo.fields { - p.unmarshal(entries[finfo.name], finfo.value(val)) + if ent, ok := entries[finfo.name]; ok { + p.unmarshal(ent, finfo.valueForWriting(val)) + } } case reflect.Map: if val.IsNil() { val.Set(reflect.MakeMap(typ)) } + if !stringType.ConvertibleTo(val.Type().Key()) { + panic(fmt.Errorf("plist: attempt to decode dictionary into map with non-string key type `%v'", val.Type().Key())) + } + for i, k := range dict.keys { sval := dict.values[i] diff --git a/vendor/modules.txt b/vendor/modules.txt index 2fce4f5c2..424d137e7 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -18,9 +18,6 @@ github.com/Microsoft/hcsshim/osversion # github.com/PuerkitoBio/rehttp v1.4.0 ## explicit; go 1.16 github.com/PuerkitoBio/rehttp -# github.com/StackExchange/wmi v1.2.1 -## explicit; go 1.13 -github.com/StackExchange/wmi # github.com/alecthomas/units v0.0.0-20211218093645-b94a6e3cc137 ## explicit; go 1.15 github.com/alecthomas/units @@ -297,15 +294,16 @@ github.com/jackc/pgtype github.com/jackc/pgx/v4 github.com/jackc/pgx/v4/internal/sanitize github.com/jackc/pgx/v4/stdlib -# github.com/jaypipes/ghw v0.16.0 +# github.com/jaypipes/ghw v0.23.0 ## explicit; go 1.21 github.com/jaypipes/ghw +github.com/jaypipes/ghw/internal/config +github.com/jaypipes/ghw/internal/log github.com/jaypipes/ghw/pkg/accelerator github.com/jaypipes/ghw/pkg/baseboard github.com/jaypipes/ghw/pkg/bios github.com/jaypipes/ghw/pkg/block github.com/jaypipes/ghw/pkg/chassis -github.com/jaypipes/ghw/pkg/context github.com/jaypipes/ghw/pkg/cpu github.com/jaypipes/ghw/pkg/gpu github.com/jaypipes/ghw/pkg/linuxdmi @@ -317,13 +315,15 @@ github.com/jaypipes/ghw/pkg/option github.com/jaypipes/ghw/pkg/pci github.com/jaypipes/ghw/pkg/pci/address github.com/jaypipes/ghw/pkg/product -github.com/jaypipes/ghw/pkg/snapshot github.com/jaypipes/ghw/pkg/topology github.com/jaypipes/ghw/pkg/unitutil +github.com/jaypipes/ghw/pkg/usb github.com/jaypipes/ghw/pkg/util -# github.com/jaypipes/pcidb v1.0.1 +# github.com/jaypipes/pcidb v1.1.1 ## explicit; go 1.21 github.com/jaypipes/pcidb +github.com/jaypipes/pcidb/internal +github.com/jaypipes/pcidb/types # github.com/jinzhu/copier v0.4.0 ## explicit; go 1.13 github.com/jinzhu/copier @@ -377,9 +377,6 @@ github.com/matttproud/golang_protobuf_extensions/v2/pbutil ## explicit; go 1.21 github.com/microcosm-cc/bluemonday github.com/microcosm-cc/bluemonday/css -# github.com/mitchellh/go-homedir v1.1.0 -## explicit -github.com/mitchellh/go-homedir # github.com/mitchellh/mapstructure v1.5.0 ## explicit; go 1.14 github.com/mitchellh/mapstructure @@ -684,7 +681,7 @@ github.com/vishvananda/netns # github.com/x448/float16 v0.8.4 ## explicit; go 1.11 github.com/x448/float16 -# github.com/yusufpapurcu/wmi v1.2.3 +# github.com/yusufpapurcu/wmi v1.2.4 ## explicit; go 1.16 github.com/yusufpapurcu/wmi # go.mongodb.org/mongo-driver v1.14.0 @@ -854,7 +851,7 @@ gorm.io/gorm/logger gorm.io/gorm/migrator gorm.io/gorm/schema gorm.io/gorm/utils -# howett.net/plist v1.0.0 +# howett.net/plist v1.0.2-0.20250314012144-ee69052608d9 ## explicit; go 1.12 howett.net/plist # k8s.io/api v0.34.3