From 3aa043ce2783d0c59fe4169c0580c840d4c45dae Mon Sep 17 00:00:00 2001 From: Riccardo Re Date: Thu, 6 Feb 2020 16:54:16 +0100 Subject: [PATCH 1/2] Windows support: block Added partial windows support to block --- block_stub.go | 2 +- block_windows.go | 233 +++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 2 + go.sum | 4 + 4 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 block_windows.go diff --git a/block_stub.go b/block_stub.go index 7225c321..8e592466 100644 --- a/block_stub.go +++ b/block_stub.go @@ -1,4 +1,4 @@ -// +build !linux,!darwin +// +build !linux,!darwin,!windows // Use and distribution licensed under the Apache license version 2. // // See the COPYING file in the root project directory for full text. diff --git a/block_windows.go b/block_windows.go new file mode 100644 index 00000000..defac106 --- /dev/null +++ b/block_windows.go @@ -0,0 +1,233 @@ +// Use and distribution licensed under the Apache license version 2. +// +// See the COPYING file in the root project directory for full text. +// + +package ghw + +import ( + "strings" + + "github.com/StackExchange/wmi" +) + +const wqlDiskDrive = "SELECT Caption, CreationClassName, Description, DeviceID, Index, InterfaceType, Manufacturer, MediaType, Model, Name, Partitions, SerialNumber, Size, TotalCylinders, TotalHeads, TotalSectors, TotalTracks, TracksPerCylinder FROM Win32_DiskDrive" + +type win32DiskDrive struct { + Caption string + CreationClassName string + Description string + DeviceID string + Index uint32 // Used to link with partition + InterfaceType string + Manufacturer string + MediaType string + Model string + Name string + Partitions int32 + SerialNumber string + Size uint64 + TotalCylinders int64 + TotalHeads int32 + TotalSectors int64 + TotalTracks int64 + TracksPerCylinder int32 +} + +const wqlDiskPartition = "SELECT Access, BlockSize, Caption, CreationClassName, Description, DeviceID, DiskIndex, Index, Name, Size, SystemName, Type FROM Win32_DiskPartition" + +type win32DiskPartition struct { + Access uint16 + BlockSize uint64 + Caption string + CreationClassName string + Description string + DeviceID string + DiskIndex uint32 // Used to link with Disk Drive + Index uint32 + Name string + Size int64 + SystemName string + Type string +} + +const wqlLogicalDiskToPartition = "SELECT Antecedent, Dependent FROM Win32_LogicalDiskToPartition" + +type win32LogicalDiskToPartition struct { + Antecedent string + Dependent string +} + +const wqlLogicalDisk = "SELECT Caption, CreationClassName, Description, DeviceID, FileSystem, FreeSpace, Name, Size, SystemName FROM Win32_LogicalDisk" + +type win32LogicalDisk struct { + Caption string + CreationClassName string + Description string + DeviceID string + FileSystem string + FreeSpace uint64 + Name string + Size uint64 + SystemName string +} + +func (ctx *context) blockFillInfo(info *BlockInfo) error { + win32DiskDriveDescriptions, err := getDiskDrives() + if err != nil { + return err + } + + win32DiskPartitionDescriptions, err := getDiskPartitions() + if err != nil { + return err + } + + win32LogicalDiskToPartitionDescriptions, err := getLogicalDisksToPartitions() + if err != nil { + return err + } + + win32LogicalDiskDescriptions, err := getLogicalDisks() + if err != nil { + return err + } + + // Converting into standard structures + disks := make([]*Disk, 0) + for _, diskdrive := range win32DiskDriveDescriptions { + disk := &Disk{ + Name: diskdrive.Name, + SizeBytes: diskdrive.Size, + PhysicalBlockSizeBytes: 0, + DriveType: toDriveType(diskdrive.MediaType), + StorageController: toStorageController(diskdrive.InterfaceType), + BusType: toBusType(diskdrive.InterfaceType), + BusPath: UNKNOWN, // TODO: add information + Vendor: UNKNOWN, // TODO: add information + Model: diskdrive.Caption, + SerialNumber: diskdrive.SerialNumber, + WWN: UNKNOWN, // TODO: add information + Partitions: make([]*Partition, 0), + } + for _, diskpartition := range win32DiskPartitionDescriptions { + // Finding disk partition linked to current disk drive + if diskdrive.Index == diskpartition.DiskIndex { + disk.PhysicalBlockSizeBytes = diskpartition.BlockSize + // Finding logical partition linked to current disk partition + for _, logicaldisk := range win32LogicalDiskDescriptions { + for _, logicaldisktodiskpartition := range win32LogicalDiskToPartitionDescriptions { + var desiredAntecedent = "\\\\" + diskpartition.SystemName + "\\root\\cimv2:" + diskpartition.CreationClassName + ".DeviceID=\"" + diskpartition.DeviceID + "\"" + var desiredDependent = "\\\\" + logicaldisk.SystemName + "\\root\\cimv2:" + logicaldisk.CreationClassName + ".DeviceID=\"" + logicaldisk.DeviceID + "\"" + if logicaldisktodiskpartition.Antecedent == desiredAntecedent && logicaldisktodiskpartition.Dependent == desiredDependent { + // Appending Partition + p := &Partition{ + Name: logicaldisk.Caption, + Label: logicaldisk.Caption, + SizeBytes: logicaldisk.Size, + MountPoint: logicaldisk.DeviceID, + Type: diskpartition.Type, + IsReadOnly: toReadOnly(diskpartition.Access), // TODO: add information + } + disk.Partitions = append(disk.Partitions, p) + break + } + } + } + } + } + disks = append(disks, disk) + } + + info.Disks = disks + var tpb uint64 + for _, d := range info.Disks { + tpb += d.SizeBytes + } + info.TotalPhysicalBytes = tpb + return nil +} + +func getDiskDrives() ([]win32DiskDrive, error) { + // Getting disks drives data from WMI + var win3232DiskDriveDescriptions []win32DiskDrive + if err := wmi.Query(wqlDiskDrive, &win3232DiskDriveDescriptions); err != nil { + return nil, err + } + return win3232DiskDriveDescriptions, nil +} + +func getDiskPartitions() ([]win32DiskPartition, error) { + // Getting disk partitions from WMI + var win32DiskPartitionDescriptions []win32DiskPartition + if err := wmi.Query(wqlDiskPartition, &win32DiskPartitionDescriptions); err != nil { + return nil, err + } + return win32DiskPartitionDescriptions, nil +} + +func getLogicalDisksToPartitions() ([]win32LogicalDiskToPartition, error) { + // Getting links between logical disks and partitions from WMI + var win32LogicalDiskToPartitionDescriptions []win32LogicalDiskToPartition + if err := wmi.Query(wqlLogicalDiskToPartition, &win32LogicalDiskToPartitionDescriptions); err != nil { + return nil, err + } + return win32LogicalDiskToPartitionDescriptions, nil +} + +func getLogicalDisks() ([]win32LogicalDisk, error) { + // Getting logical disks from WMI + var win32LogicalDiskDescriptions []win32LogicalDisk + if err := wmi.Query(wqlLogicalDisk, &win32LogicalDiskDescriptions); err != nil { + return nil, err + } + return win32LogicalDiskDescriptions, nil +} + +// TODO: improve +func toDriveType(mediaType string) DriveType { + var driveType DriveType + mediaType = strings.ToLower(mediaType) + if strings.Contains(mediaType, "fixed") || strings.Contains(mediaType, "ssd") { + driveType = DRIVE_TYPE_SSD + } else if strings.ContainsAny(mediaType, "hdd") { + driveType = DRIVE_TYPE_HDD + } else { + driveType = DRIVE_TYPE_UNKNOWN + } + return driveType +} + +// TODO: improve +func toStorageController(interfaceType string) StorageController { + var storageController StorageController + switch interfaceType { + case "SCSI": + storageController = STORAGE_CONTROLLER_SCSI + case "IDE": + storageController = STORAGE_CONTROLLER_IDE + default: + storageController = STORAGE_CONTROLLER_UNKNOWN + } + return storageController +} + +// TODO: improve +func toBusType(interfaceType string) BusType { + var busType BusType + switch interfaceType { + case "SCSI": + busType = BUS_TYPE_SCSI + case "IDE": + busType = BUS_TYPE_IDE + default: + busType = BUS_TYPE_UNKNOWN + } + return busType +} + +// TODO: improve +func toReadOnly(access uint16) bool { + // See Access property from: https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskpartition + return access == 0x1 +} diff --git a/go.mod b/go.mod index 3e2bc9de..f3d0e255 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,9 @@ module github.com/jaypipes/ghw go 1.12 require ( + github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d github.com/ghodss/yaml v1.0.0 + github.com/go-ole/go-ole v1.2.4 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jaypipes/pcidb v0.5.0 github.com/pkg/errors v0.8.0 diff --git a/go.sum b/go.sum index c37c2768..8833173f 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= +github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= +github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jaypipes/pcidb v0.5.0 h1:4W5gZ+G7QxydevI8/MmmKdnIPJpURqJ2JNXTzfLxF5c= From 69aed945e549f177e2cb1587ba681ae1f3f6a492 Mon Sep 17 00:00:00 2001 From: Riccardo Re Date: Fri, 7 Feb 2020 08:14:38 +0100 Subject: [PATCH 2/2] Feature: Partitions and UsableBytes (Windows Only) When collecting HW informations about disks it's also very usefull to understand how much free space is available on each partition. Here a quick example based on my "Windows support: block" https://github.com/jaypipes/ghw/pull/156 --- block.go | 15 ++++++++------- block_windows.go | 13 +++++++------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/block.go b/block.go index 001ba8d7..a6b7b251 100644 --- a/block.go +++ b/block.go @@ -108,13 +108,14 @@ type Disk struct { // Partition describes a logical division of a Disk. type Partition struct { - Disk *Disk `json:"-"` - Name string `json:"name"` - Label string `json:"label"` - MountPoint string `json:"mount_point"` - SizeBytes uint64 `json:"size_bytes"` - Type string `json:"type"` - IsReadOnly bool `json:"read_only"` + Disk *Disk `json:"-"` + Name string `json:"name"` + Label string `json:"label"` + MountPoint string `json:"mount_point"` + SizeBytes uint64 `json:"size_bytes"` + UsableBytes uint64 `json:"usable_bytes"` + Type string `json:"type"` + IsReadOnly bool `json:"read_only"` } // BlockInfo describes all disk drives and partitions in the host system. diff --git a/block_windows.go b/block_windows.go index defac106..4a1f0b2c 100644 --- a/block_windows.go +++ b/block_windows.go @@ -122,12 +122,13 @@ func (ctx *context) blockFillInfo(info *BlockInfo) error { if logicaldisktodiskpartition.Antecedent == desiredAntecedent && logicaldisktodiskpartition.Dependent == desiredDependent { // Appending Partition p := &Partition{ - Name: logicaldisk.Caption, - Label: logicaldisk.Caption, - SizeBytes: logicaldisk.Size, - MountPoint: logicaldisk.DeviceID, - Type: diskpartition.Type, - IsReadOnly: toReadOnly(diskpartition.Access), // TODO: add information + Name: logicaldisk.Caption, + Label: logicaldisk.Caption, + SizeBytes: logicaldisk.Size, + UsableBytes: logicaldisk.FreeSpace, + MountPoint: logicaldisk.DeviceID, + Type: diskpartition.Type, + IsReadOnly: toReadOnly(diskpartition.Access), // TODO: add information } disk.Partitions = append(disk.Partitions, p) break