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 }