github.com/jaypipes/ghw@v0.21.1/pkg/block/block_windows.go (about)

     1  // Use and distribution licensed under the Apache license version 2.
     2  //
     3  // See the COPYING file in the root project directory for full text.
     4  //
     5  
     6  package block
     7  
     8  import (
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/yusufpapurcu/wmi"
    13  
    14  	"github.com/jaypipes/ghw/pkg/util"
    15  )
    16  
    17  type physicalDiskMediaType int
    18  
    19  const (
    20  	physicalDiskMediaTypeUnspecified physicalDiskMediaType = 0
    21  	physicalDiskMediaTypeHDD         physicalDiskMediaType = 3
    22  	physicalDiskMediaTypeSSD         physicalDiskMediaType = 4
    23  	physicalDiskMediaTypeSCM         physicalDiskMediaType = 5
    24  )
    25  
    26  func (dt physicalDiskMediaType) ToDriveType() DriveType {
    27  	switch dt {
    28  	case physicalDiskMediaTypeUnspecified:
    29  		return DriveTypeUnknown
    30  	case physicalDiskMediaTypeHDD:
    31  		return DriveTypeHDD
    32  	case physicalDiskMediaTypeSSD:
    33  		return DriveTypeSSD
    34  	case physicalDiskMediaTypeSCM:
    35  		return DriveTypeUnknown
    36  	}
    37  	return DriveTypeUnknown
    38  }
    39  
    40  const wqlDiskDrive = "SELECT Caption, CreationClassName, DefaultBlockSize, Description, DeviceID, Index, InterfaceType, Manufacturer, MediaType, Model, Name, Partitions, SerialNumber, Size, TotalCylinders, TotalHeads, TotalSectors, TotalTracks, TracksPerCylinder FROM Win32_DiskDrive"
    41  
    42  type win32DiskDrive struct {
    43  	Caption           *string
    44  	CreationClassName *string
    45  	DefaultBlockSize  *uint64
    46  	Description       *string
    47  	DeviceID          *string
    48  	Index             *uint32 // Used to link with partition
    49  	InterfaceType     *string
    50  	Manufacturer      *string
    51  	MediaType         *string
    52  	Model             *string
    53  	Name              *string
    54  	Partitions        *int32
    55  	SerialNumber      *string
    56  	Size              *uint64
    57  	TotalCylinders    *int64
    58  	TotalHeads        *int32
    59  	TotalSectors      *int64
    60  	TotalTracks       *int64
    61  	TracksPerCylinder *int32
    62  }
    63  
    64  const wqlDiskPartition = "SELECT Access, BlockSize, Caption, CreationClassName, Description, DeviceID, DiskIndex, Index, Name, Size, SystemName, Type FROM Win32_DiskPartition"
    65  
    66  type win32DiskPartition struct {
    67  	Access            *uint16
    68  	BlockSize         *uint64
    69  	Caption           *string
    70  	CreationClassName *string
    71  	Description       *string
    72  	DeviceID          *string
    73  	DiskIndex         *uint32 // Used to link with Disk Drive
    74  	Index             *uint32
    75  	Name              *string
    76  	Size              *int64
    77  	SystemName        *string
    78  	Type              *string
    79  }
    80  
    81  const wqlLogicalDiskToPartition = "SELECT Antecedent, Dependent FROM Win32_LogicalDiskToPartition"
    82  
    83  type win32LogicalDiskToPartition struct {
    84  	Antecedent *string
    85  	Dependent  *string
    86  }
    87  
    88  const wqlLogicalDisk = "SELECT Caption, CreationClassName, Description, DeviceID, FileSystem, FreeSpace, Name, Size, SystemName, VolumeName, VolumeSerialNumber  FROM Win32_LogicalDisk"
    89  
    90  type win32LogicalDisk struct {
    91  	Caption            *string
    92  	CreationClassName  *string
    93  	Description        *string
    94  	DeviceID           *string
    95  	FileSystem         *string
    96  	FreeSpace          *uint64
    97  	Name               *string
    98  	Size               *uint64
    99  	SystemName         *string
   100  	VolumeName         *string
   101  	VolumeSerialNumber *string
   102  }
   103  
   104  const wqlPhysicalDisk = "SELECT DeviceId, MediaType FROM MSFT_PhysicalDisk"
   105  
   106  type win32PhysicalDisk struct {
   107  	DeviceId  string
   108  	MediaType physicalDiskMediaType
   109  }
   110  
   111  func (i *Info) load() error {
   112  	win32DiskDriveDescriptions, err := getDiskDrives()
   113  	if err != nil {
   114  		return err
   115  	}
   116  
   117  	win32DiskPartitionDescriptions, err := getDiskPartitions()
   118  	if err != nil {
   119  		return err
   120  	}
   121  
   122  	win32LogicalDiskToPartitionDescriptions, err := getLogicalDisksToPartitions()
   123  	if err != nil {
   124  		return err
   125  	}
   126  
   127  	win32LogicalDiskDescriptions, err := getLogicalDisks()
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	win32PhysicalDisks, err := getPhysicalDisks()
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	// Converting into standard structures
   138  	disks := make([]*Disk, 0)
   139  	for _, diskdrive := range win32DiskDriveDescriptions {
   140  		var physicalDiskMediaType physicalDiskMediaType
   141  		for _, physicalDisk := range win32PhysicalDisks {
   142  			if id, err := strconv.Atoi(physicalDisk.DeviceId); err != nil {
   143  				return err
   144  			} else if uint32(id) == *diskdrive.Index {
   145  				physicalDiskMediaType = physicalDisk.MediaType
   146  			}
   147  		}
   148  		disk := &Disk{
   149  			Name:                   strings.TrimSpace(*diskdrive.DeviceID),
   150  			SizeBytes:              *diskdrive.Size,
   151  			PhysicalBlockSizeBytes: *diskdrive.DefaultBlockSize,
   152  			DriveType:              toDriveType(physicalDiskMediaType, *diskdrive.MediaType, *diskdrive.Caption),
   153  			StorageController:      toStorageController(*diskdrive.InterfaceType),
   154  			BusPath:                util.UNKNOWN, // TODO: add information
   155  			NUMANodeID:             -1,
   156  			Vendor:                 strings.TrimSpace(*diskdrive.Manufacturer),
   157  			Model:                  strings.TrimSpace(*diskdrive.Caption),
   158  			SerialNumber:           strings.TrimSpace(*diskdrive.SerialNumber),
   159  			WWN:                    util.UNKNOWN, // TODO: add information
   160  			WWNNoExtension:         util.UNKNOWN, // TODO: add information
   161  			Partitions:             make([]*Partition, 0),
   162  		}
   163  		for _, diskpartition := range win32DiskPartitionDescriptions {
   164  			// Finding disk partition linked to current disk drive
   165  			if diskdrive.Index == nil || diskpartition.DiskIndex == nil {
   166  				continue
   167  			}
   168  			if *diskdrive.Index == *diskpartition.DiskIndex {
   169  				disk.PhysicalBlockSizeBytes = *diskpartition.BlockSize
   170  				// Finding logical partition linked to current disk partition
   171  				for _, logicaldisk := range win32LogicalDiskDescriptions {
   172  					for _, logicaldisktodiskpartition := range win32LogicalDiskToPartitionDescriptions {
   173  						var desiredAntecedent = "\\\\" + *diskpartition.SystemName + "\\root\\cimv2:" + *diskpartition.CreationClassName + ".DeviceID=\"" + *diskpartition.DeviceID + "\""
   174  						var desiredDependent = "\\\\" + *logicaldisk.SystemName + "\\root\\cimv2:" + *logicaldisk.CreationClassName + ".DeviceID=\"" + *logicaldisk.DeviceID + "\""
   175  						if *logicaldisktodiskpartition.Antecedent == desiredAntecedent && *logicaldisktodiskpartition.Dependent == desiredDependent {
   176  							// Appending Partition
   177  							p := &Partition{
   178  								Disk:       disk,
   179  								Name:       strings.TrimSpace(*logicaldisk.VolumeName),
   180  								Label:      strings.TrimSpace(*logicaldisk.Caption),
   181  								SizeBytes:  *logicaldisk.Size,
   182  								MountPoint: *logicaldisk.DeviceID,
   183  								Type:       *diskpartition.Type,
   184  								IsReadOnly: toReadOnly(*diskpartition.Access),
   185  								UUID:       *logicaldisk.VolumeSerialNumber,
   186  							}
   187  							disk.Partitions = append(disk.Partitions, p)
   188  							break
   189  						}
   190  					}
   191  				}
   192  			}
   193  		}
   194  		disks = append(disks, disk)
   195  	}
   196  
   197  	i.Disks = disks
   198  	var tsb uint64
   199  	for _, d := range i.Disks {
   200  		tsb += d.SizeBytes
   201  	}
   202  	i.TotalSizeBytes = tsb
   203  	i.TotalPhysicalBytes = tsb
   204  	return nil
   205  }
   206  
   207  func getDiskDrives() ([]win32DiskDrive, error) {
   208  	// Getting disks drives data from WMI
   209  	var win3232DiskDriveDescriptions []win32DiskDrive
   210  	if err := wmi.Query(wqlDiskDrive, &win3232DiskDriveDescriptions); err != nil {
   211  		return nil, err
   212  	}
   213  	return win3232DiskDriveDescriptions, nil
   214  }
   215  
   216  func getDiskPartitions() ([]win32DiskPartition, error) {
   217  	// Getting disk partitions from WMI
   218  	var win32DiskPartitionDescriptions []win32DiskPartition
   219  	if err := wmi.Query(wqlDiskPartition, &win32DiskPartitionDescriptions); err != nil {
   220  		return nil, err
   221  	}
   222  	return win32DiskPartitionDescriptions, nil
   223  }
   224  
   225  func getLogicalDisksToPartitions() ([]win32LogicalDiskToPartition, error) {
   226  	// Getting links between logical disks and partitions from WMI
   227  	var win32LogicalDiskToPartitionDescriptions []win32LogicalDiskToPartition
   228  	if err := wmi.Query(wqlLogicalDiskToPartition, &win32LogicalDiskToPartitionDescriptions); err != nil {
   229  		return nil, err
   230  	}
   231  	return win32LogicalDiskToPartitionDescriptions, nil
   232  }
   233  
   234  func getLogicalDisks() ([]win32LogicalDisk, error) {
   235  	// Getting logical disks from WMI
   236  	var win32LogicalDiskDescriptions []win32LogicalDisk
   237  	if err := wmi.Query(wqlLogicalDisk, &win32LogicalDiskDescriptions); err != nil {
   238  		return nil, err
   239  	}
   240  	return win32LogicalDiskDescriptions, nil
   241  }
   242  
   243  func getPhysicalDisks() ([]win32PhysicalDisk, error) {
   244  	// Getting physical disks from WMI
   245  	var win32PhysicalDisks []win32PhysicalDisk
   246  	if err := wmi.QueryNamespace(wqlPhysicalDisk, &win32PhysicalDisks, "root\\Microsoft\\Windows\\Storage"); err != nil {
   247  		return nil, err
   248  	}
   249  	return win32PhysicalDisks, nil
   250  }
   251  
   252  func toDriveType(physicalDiskMediaType physicalDiskMediaType, mediaType string, caption string) DriveType {
   253  	if driveType := physicalDiskMediaType.ToDriveType(); driveType != DriveTypeUnknown {
   254  		return driveType
   255  	}
   256  
   257  	mediaType = strings.ToLower(mediaType)
   258  	caption = strings.ToLower(caption)
   259  	if strings.Contains(mediaType, "fixed") || strings.Contains(mediaType, "ssd") || strings.Contains(caption, "ssd") {
   260  		return DriveTypeSSD
   261  	} else if strings.ContainsAny(mediaType, "hdd") {
   262  		return DriveTypeHDD
   263  	}
   264  	return DriveTypeUnknown
   265  }
   266  
   267  // TODO: improve
   268  func toStorageController(interfaceType string) StorageController {
   269  	var storageController StorageController
   270  	switch interfaceType {
   271  	case "SCSI":
   272  		storageController = StorageControllerSCSI
   273  	case "IDE":
   274  		storageController = StorageControllerIDE
   275  	default:
   276  		storageController = StorageControllerUnknown
   277  	}
   278  	return storageController
   279  }
   280  
   281  // TODO: improve
   282  func toReadOnly(access uint16) bool {
   283  	// See Access property from: https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskpartition
   284  	return access == 0x1
   285  }