From 47bb2d9dd90fcbcdbb8c0e22a1a9aa516a22a802 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Fri, 27 Feb 2026 15:28:05 +0100 Subject: [PATCH 1/6] validate collected STORAGE_DEVICE_NUMBER structs better the code was previously checking for associations between drive letters and collected STORAGE_DEVICE_NUMBER struct, and then relying on the generated handle \\.\PhysicalDrive[DeviceNumber] throwing an error for the drive now check STORAGE_DEVICE_NUMBER structs in three two ways. temporary devices seem to have DeviceNumber set to 0, but have PartitionNumber set above 32768, remove these devices. DeviceType is also in the returned struct. Check if it matches the FILE_DEVICE_DISK value. the code was iterating from 0 to 32 for deviceNumber and checking if it had a driveLetter. this was causing some drive letters to be skipped, since ultiple drive letters might belong to the same physical drive collect valid storageDeviceNumber structs into another map from drive letter to the struct. then iterate over this map from scratch --- pkg/snclient/check_drive_io_windows.go | 2 +- pkg/snclient/task_check_system_windows.go | 80 +++++++++++++++++------ 2 files changed, 61 insertions(+), 21 deletions(-) diff --git a/pkg/snclient/check_drive_io_windows.go b/pkg/snclient/check_drive_io_windows.go index 0762907e..032bf638 100644 --- a/pkg/snclient/check_drive_io_windows.go +++ b/pkg/snclient/check_drive_io_windows.go @@ -11,7 +11,7 @@ import ( ) func getIOCounters(_ context.Context) (any, error) { - return ioCountersWindows() + return ioCountersWindows(), nil } func (l *CheckDriveIO) buildEntry(snc *Agent, diskIOCounters any, deviceLogicalNameOrLetter string, entry map[string]string, _ []disk.PartitionStat) (foundDisk bool) { diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index a6e6dad5..6a1a8f76 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -118,25 +118,46 @@ func init() { } // names: drive names to filter to. if empty, all drives are discovered -func ioCountersWindows(names ...string) (map[string]IOCountersStatWindows, error) { +// tries to match physical drives only +func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { drivemap := make(map[string]IOCountersStatWindows, 0) var dPerformance diskPerformance - // For getting a handle to the root of the drive, specify the path as \\.\PhysicalDriveX . - // This seems to be better at picking the correct drives that can do IoctlCalls + // filter the real physical drives from all gathered storageDeviceNumbers + validStorageDeviceNumbers := make(map[string]storageDeviceNumberStruct) + + // first 32 devices are more likely to be real physical drives for deviceNumber := range uint32(32) { - // Skip deviceNumbers that do not have a drive letter - deviceLetter := "" - for letter, storageDeviceNumber := range storageDeviceNumbers { - if storageDeviceNumber.DeviceNumber == deviceNumber { - deviceLetter = letter + // multiple letters might share the same storage device if disk is partitioned + for letter, sdn := range storageDeviceNumbers { + if sdn.DeviceNumber != deviceNumber { + continue } + + // seems to be reserved for non-physical drives + // for example a CD drive looked like this: + // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 + if sdn.PartitionNumber > 32 { + log.Tracef("Device Invalid for disk IO, likely non-drive. DeviceNumber: %d, DeviceType: %d, Partition Number: %d", sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue + } + + // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h + // FILE_DEVICE_DISK = 7 + if sdn.DeviceType != 7 { + log.Tracef("Device Invalid for disk IO, deviceType is not a disk. DeviceNumber: %d, DeviceType: %d, Partition Number: %d", sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue + } + + validStorageDeviceNumbers[letter] = sdn } - if deviceLetter == "" { - continue - } + } + + // For getting a handle to the root of the drive, specify the path as \\.\PhysicalDriveX . + // This seems to be better at picking the correct drives that can do IoctlCalls + for deviceLetter, sdn := range validStorageDeviceNumbers { - handlePath := `\\.\PhysicalDrive` + fmt.Sprintf("%d", deviceNumber) + handlePath := `\\.\PhysicalDrive` + fmt.Sprintf("%d", sdn.DeviceNumber) handle, err := windows.CreateFile(windows.StringToUTF16Ptr(handlePath), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0) if err != nil { @@ -144,9 +165,11 @@ func ioCountersWindows(names ...string) (map[string]IOCountersStatWindows, error continue } - return drivemap, fmt.Errorf("error when creating a file handle on handlePath: %s, err: %w", handlePath, err) + log.Debugf("Error when creating a file handle on handlePath: %s, err: %s", handlePath, err.Error()) + continue } if handle == windows.InvalidHandle { + log.Debugf("Invalid handle for PhysicalDrive %d with path: %s", sdn.DeviceNumber, handlePath) continue } @@ -155,13 +178,28 @@ func ioCountersWindows(names ...string) (map[string]IOCountersStatWindows, error err = windows.DeviceIoControl(handle, IOctlDiskPerformance, nil, 0, (*byte)(unsafe.Pointer(&dPerformance)), uint32(unsafe.Sizeof(dPerformance)), &diskPerformanceSize, nil) if err != nil { if errors.Is(err, windows.ERROR_INVALID_FUNCTION) { + log.Debugf("IOCTL_DISK_PERFORMANCE not supported for PhysicalDrive%d", sdn.DeviceNumber) + errClose := windows.CloseHandle(handle) + if errClose != nil { + log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) + } continue } if errors.Is(err, windows.ERROR_NOT_SUPPORTED) { + log.Debugf("IOCTL_DISK_PERFORMANCE not supported for PhysicalDrive%d", sdn.DeviceNumber) + errClose := windows.CloseHandle(handle) + if errClose != nil { + log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) + } continue } - return drivemap, fmt.Errorf("error when calling IoctlDiskPerformance with a open handle to: %s, err: %w", handlePath, err) + log.Debugf("Error when calling IoctlDiskPerformance with a open handle to: %s, err: %s", handlePath, err.Error()) + errClose := windows.CloseHandle(handle) + if errClose != nil { + log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) + } + continue } err = windows.CloseHandle(handle) @@ -192,7 +230,7 @@ func ioCountersWindows(names ...string) (map[string]IOCountersStatWindows, error } } - return drivemap, nil + return drivemap } // This is a struct that will be filled with the Ioctl IOCTL_STORAGE_GET_DEVICE_NUMBER call. @@ -244,7 +282,11 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { (*byte)(unsafe.Pointer(&storageDeviceNumber)), uint32(unsafe.Sizeof(storageDeviceNumber)), &bytesReturned, nil) if err != nil { log.Tracef("Logical drive %s, got an error from Ioctl IOCTL_STORAGE_GET_DEVICE_NUMBER. Likely has no physical device e.g VirtioFS/Network. Err: %s\n", logicalDriveLetter, err.Error()) - + // Close handle before continuing + errClose := windows.CloseHandle(handle) + if errClose != nil { + log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) + } continue } @@ -254,6 +296,7 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { } mappings[logicalDriveLetter] = storageDeviceNumber + log.Debugf("Mapped logical drive letter %s to device number %d , partition number: %d", logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.PartitionNumber) } return mappings @@ -263,11 +306,8 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { // Until the gopsutil is patched, use this version // The function reports these attributes correctly func (c *CheckSystemHandler) addDiskStats(create bool) { - diskIOCounters, err := ioCountersWindows() + diskIOCounters := ioCountersWindows() // do not create the counters if there is an error - if err != nil { - return - } if create { for diskName := range diskIOCounters { From 1b9275a0789e72cfa6f67b7e601f40796001fa47 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Mon, 2 Mar 2026 11:42:22 +0100 Subject: [PATCH 2/6] filter out devices to watch on init() and cache the results instead of every invocation ioCountersWindows function. --- pkg/snclient/task_check_system_windows.go | 75 +++++++++++++---------- 1 file changed, 43 insertions(+), 32 deletions(-) diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index 6a1a8f76..dc5635dd 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -82,8 +82,12 @@ type IOCountersStatWindows struct { // Therefore, the frequency need only be queried upon application initialization, and the result can be cached. var performanceFrequency = uint64(0) +// All gathered storage devices var storageDeviceNumbers map[string]storageDeviceNumberStruct +// Filtered storage devices to watch, used in disk stats +var storageDeviceNumbersToWatch map[string]storageDeviceNumberStruct + var ( kernel32DLL = syscall.NewLazyDLL("kernel32.dll") QueryPerformanceFrequencyFunc = kernel32DLL.NewProc("QueryPerformanceFrequency") @@ -114,6 +118,8 @@ func init() { storageDeviceNumbers = getDriveStorageDeviceNumbers() + storageDeviceNumbersToWatch = getStorageDeviceNumbersToWatch() + performanceFrequency = getPerformanceFrequency() } @@ -123,39 +129,9 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { drivemap := make(map[string]IOCountersStatWindows, 0) var dPerformance diskPerformance - // filter the real physical drives from all gathered storageDeviceNumbers - validStorageDeviceNumbers := make(map[string]storageDeviceNumberStruct) - - // first 32 devices are more likely to be real physical drives - for deviceNumber := range uint32(32) { - // multiple letters might share the same storage device if disk is partitioned - for letter, sdn := range storageDeviceNumbers { - if sdn.DeviceNumber != deviceNumber { - continue - } - - // seems to be reserved for non-physical drives - // for example a CD drive looked like this: - // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 - if sdn.PartitionNumber > 32 { - log.Tracef("Device Invalid for disk IO, likely non-drive. DeviceNumber: %d, DeviceType: %d, Partition Number: %d", sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) - continue - } - - // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h - // FILE_DEVICE_DISK = 7 - if sdn.DeviceType != 7 { - log.Tracef("Device Invalid for disk IO, deviceType is not a disk. DeviceNumber: %d, DeviceType: %d, Partition Number: %d", sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) - continue - } - - validStorageDeviceNumbers[letter] = sdn - } - } - // For getting a handle to the root of the drive, specify the path as \\.\PhysicalDriveX . // This seems to be better at picking the correct drives that can do IoctlCalls - for deviceLetter, sdn := range validStorageDeviceNumbers { + for deviceLetter, sdn := range storageDeviceNumbersToWatch { handlePath := `\\.\PhysicalDrive` + fmt.Sprintf("%d", sdn.DeviceNumber) @@ -296,12 +272,47 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { } mappings[logicalDriveLetter] = storageDeviceNumber - log.Debugf("Mapped logical drive letter %s to device number %d , partition number: %d", logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.PartitionNumber) + log.Debugf("Adding to storageDeviceNumber map. Letter: %s, Device Number: %d, DeviceType: %d, Partition Number: %d", logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.DeviceType, storageDeviceNumber.PartitionNumber) } return mappings } +func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { + // filter the real physical drives from all gathered storageDeviceNumbers + storageDeviceNumbersToWatch := make(map[string]storageDeviceNumberStruct) + + // first 32 devices are more likely to be real physical drives + for deviceNumber := range uint32(32) { + // multiple letters might share the same storage device if disk is partitioned + for letter, sdn := range storageDeviceNumbers { + if sdn.DeviceNumber != deviceNumber { + continue + } + + // seems to be reserved for non-physical drives + // for example a CD drive looked like this: + // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 + if sdn.PartitionNumber > 32 { + log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue + } + + // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h + // FILE_DEVICE_DISK = 7 + if sdn.DeviceType != 7 { + log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue + } + + log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + storageDeviceNumbersToWatch[letter] = sdn + } + } + + return storageDeviceNumbersToWatch +} + // Windows uses an patched version of gopsutil disk.IOCounters() stored here // Until the gopsutil is patched, use this version // The function reports these attributes correctly From 3c892b4859466ca2fa548365a3b2d8fd48bd1100 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Mon, 2 Mar 2026 13:23:14 +0100 Subject: [PATCH 3/6] linter fixes --- pkg/snclient/task_check_system_windows.go | 24 ++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index dc5635dd..4e57d80d 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -125,6 +125,8 @@ func init() { // names: drive names to filter to. if empty, all drives are discovered // tries to match physical drives only +// +//nolint:gocognit // checking every handle is good practice func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { drivemap := make(map[string]IOCountersStatWindows, 0) var dPerformance diskPerformance @@ -132,7 +134,6 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { // For getting a handle to the root of the drive, specify the path as \\.\PhysicalDriveX . // This seems to be better at picking the correct drives that can do IoctlCalls for deviceLetter, sdn := range storageDeviceNumbersToWatch { - handlePath := `\\.\PhysicalDrive` + fmt.Sprintf("%d", sdn.DeviceNumber) handle, err := windows.CreateFile(windows.StringToUTF16Ptr(handlePath), 0, windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0) @@ -142,16 +143,19 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { } log.Debugf("Error when creating a file handle on handlePath: %s, err: %s", handlePath, err.Error()) + continue } if handle == windows.InvalidHandle { log.Debugf("Invalid handle for PhysicalDrive %d with path: %s", sdn.DeviceNumber, handlePath) + continue } var diskPerformanceSize uint32 const IOctlDiskPerformance = 0x70020 err = windows.DeviceIoControl(handle, IOctlDiskPerformance, nil, 0, (*byte)(unsafe.Pointer(&dPerformance)), uint32(unsafe.Sizeof(dPerformance)), &diskPerformanceSize, nil) + //nolint:nestif // checking if handles are closed is good practice if err != nil { if errors.Is(err, windows.ERROR_INVALID_FUNCTION) { log.Debugf("IOCTL_DISK_PERFORMANCE not supported for PhysicalDrive%d", sdn.DeviceNumber) @@ -159,6 +163,7 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { if errClose != nil { log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) } + continue } if errors.Is(err, windows.ERROR_NOT_SUPPORTED) { @@ -167,6 +172,7 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { if errClose != nil { log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) } + continue } @@ -175,6 +181,7 @@ func ioCountersWindows(names ...string) map[string]IOCountersStatWindows { if errClose != nil { log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) } + continue } @@ -263,6 +270,7 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { if errClose != nil { log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) } + continue } @@ -272,7 +280,8 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { } mappings[logicalDriveLetter] = storageDeviceNumber - log.Debugf("Adding to storageDeviceNumber map. Letter: %s, Device Number: %d, DeviceType: %d, Partition Number: %d", logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.DeviceType, storageDeviceNumber.PartitionNumber) + log.Debugf("Adding to storageDeviceNumber map. Letter: %s, Device Number: %d, DeviceType: %d, Partition Number: %d", + logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.DeviceType, storageDeviceNumber.PartitionNumber) } return mappings @@ -294,18 +303,23 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { // for example a CD drive looked like this: // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 if sdn.PartitionNumber > 32 { - log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue } // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h // FILE_DEVICE_DISK = 7 if sdn.DeviceType != 7 { - log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue } - log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) storageDeviceNumbersToWatch[letter] = sdn } } From ecc3fd5e9bbfdef5e3483195bb0858abe86d1b6e Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Mon, 2 Mar 2026 13:39:58 +0100 Subject: [PATCH 4/6] check the deviceNumber < 32 directly --- pkg/snclient/task_check_system_windows.go | 51 +++++++++++------------ 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index 4e57d80d..44c98c12 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -291,37 +291,36 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { // filter the real physical drives from all gathered storageDeviceNumbers storageDeviceNumbersToWatch := make(map[string]storageDeviceNumberStruct) - // first 32 devices are more likely to be real physical drives - for deviceNumber := range uint32(32) { - // multiple letters might share the same storage device if disk is partitioned - for letter, sdn := range storageDeviceNumbers { - if sdn.DeviceNumber != deviceNumber { - continue - } - - // seems to be reserved for non-physical drives - // for example a CD drive looked like this: - // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 - if sdn.PartitionNumber > 32 { - log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) - - continue - } + for letter, sdn := range storageDeviceNumbers { + // real physical drives seem to have the first 32 deviceNumbers reserved for them + if sdn.DeviceNumber > 32 { + log.Tracef("Device unfit to watch, is likely not a drive due to high deviceNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + continue + } - // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h - // FILE_DEVICE_DISK = 7 - if sdn.DeviceType != 7 { - log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + // seems to be reserved for non-physical drives + // for example a CD drive looked like this: + // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 + if sdn.PartitionNumber > 32 { + log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) - continue - } + continue + } - log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h + // FILE_DEVICE_DISK = 7 + if sdn.DeviceType != 7 { + log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) - storageDeviceNumbersToWatch[letter] = sdn + + continue } + + log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + storageDeviceNumbersToWatch[letter] = sdn } return storageDeviceNumbersToWatch From e768e5a10011ec64a58915c37a077618ce2b880c Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Mon, 2 Mar 2026 14:17:23 +0100 Subject: [PATCH 5/6] save logs during system check init() functions and print them during actual runtime at CheckSystemHandler.Init --- pkg/snclient/task_check_system.go | 7 ++++ pkg/snclient/task_check_system_windows.go | 39 +++++++++++++---------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/pkg/snclient/task_check_system.go b/pkg/snclient/task_check_system.go index f79f6e60..139c1776 100644 --- a/pkg/snclient/task_check_system.go +++ b/pkg/snclient/task_check_system.go @@ -33,6 +33,11 @@ var DefaultSystemTaskConfig = ConfigData{ // non-physical drives are not added to IO counters var StorageDevicesToWatch []string +// Logs written during init(). Since logging to file is not set up yet, +// they print out to stdout and pollute some tests that check how the stdout looks +// save them here and then print them out in CheckSystemHandler.Init +var taskCheckSystemInitLogs []string + func init() { // gopsutil on Linux seems to be reading /proc/partitions // Then it adds more info according to /sys/class/block//* @@ -102,6 +107,8 @@ func (c *CheckSystemHandler) Init(snc *Agent, section *ConfigSection, _ *Config, c.snc = snc c.stopChannel = make(chan bool) + log.Debugf("Logs saved during System handler init() functions:\n%s", strings.Join(taskCheckSystemInitLogs, "\n")) + bufferLength, _, err := section.GetDuration("default buffer length") if err != nil { return fmt.Errorf("default buffer length: %s", err.Error()) diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index 44c98c12..93683dad 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -97,8 +97,7 @@ func getPerformanceFrequency() (performanceFrequency uint64) { returnValue, _, _ := QueryPerformanceFrequencyFunc.Call(uintptr(unsafe.Pointer(&performanceFrequency))) if returnValue == 0 { - log.Debugf("Could not get performance counter frequency") - + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, "Could not get performance counter frequency") return 0 } @@ -250,7 +249,8 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { windows.FILE_SHARE_READ|windows.FILE_SHARE_WRITE, nil, windows.OPEN_EXISTING, 0, 0) if err != nil { - log.Tracef("Logical drive %s, got an error while getting a handle to %s, err: %s\n", logicalDriveLetter, handlePath, err.Error()) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Logical drive %s, got an error while getting a handle to %s, err: %s\n", logicalDriveLetter, handlePath, err.Error())) continue } @@ -264,11 +264,14 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { err = windows.DeviceIoControl(handle, IOctlStorageGetDeviceNumber, nil, 0, (*byte)(unsafe.Pointer(&storageDeviceNumber)), uint32(unsafe.Sizeof(storageDeviceNumber)), &bytesReturned, nil) if err != nil { - log.Tracef("Logical drive %s, got an error from Ioctl IOCTL_STORAGE_GET_DEVICE_NUMBER. Likely has no physical device e.g VirtioFS/Network. Err: %s\n", logicalDriveLetter, err.Error()) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Logical drive %s, got an error from Ioctl IOCTL_STORAGE_GET_DEVICE_NUMBER. Likely has no physical device e.g VirtioFS/Network. Err: %s\n", + logicalDriveLetter, err.Error())) // Close handle before continuing errClose := windows.CloseHandle(handle) if errClose != nil { - log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error()) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Error when closing handle, handlePath: %s, err: %s", handlePath, errClose.Error())) } continue @@ -276,12 +279,13 @@ func getDriveStorageDeviceNumbers() map[string]storageDeviceNumberStruct { err = windows.CloseHandle(handle) if err != nil { - log.Debugf("Error when closing handle, handlePath: %s, err: %s", handlePath, err.Error()) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, fmt.Sprintf("Error when closing handle, handlePath: %s, err: %s", handlePath, err.Error())) } mappings[logicalDriveLetter] = storageDeviceNumber - log.Debugf("Adding to storageDeviceNumber map. Letter: %s, Device Number: %d, DeviceType: %d, Partition Number: %d", - logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.DeviceType, storageDeviceNumber.PartitionNumber) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Adding to storageDeviceNumber map. Letter: %s, Device Number: %d, DeviceType: %d, Partition Number: %d", + logicalDriveLetter, storageDeviceNumber.DeviceNumber, storageDeviceNumber.DeviceType, storageDeviceNumber.PartitionNumber)) } return mappings @@ -294,8 +298,9 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { for letter, sdn := range storageDeviceNumbers { // real physical drives seem to have the first 32 deviceNumbers reserved for them if sdn.DeviceNumber > 32 { - log.Tracef("Device unfit to watch, is likely not a drive due to high deviceNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, fmt.Sprintf("Device unfit to watch, is likely not a drive due to high deviceNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) + continue } @@ -303,8 +308,8 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { // for example a CD drive looked like this: // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 if sdn.PartitionNumber > 32 { - log.Tracef("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, fmt.Sprintf("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) continue } @@ -312,14 +317,16 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { // C:\Program Files (x86)\Windows Kits\10\Include\10.0.26100.0\um\winioctl.h // FILE_DEVICE_DISK = 7 if sdn.DeviceType != 7 { - log.Tracef("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Device unfit to watch, its deviceType is not a disk. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) continue } - log.Debugf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Adding to storageDeviceNumbersToWatch. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) storageDeviceNumbersToWatch[letter] = sdn } From e547463a725ee26f8958138e330cbbe5f09d99a3 Mon Sep 17 00:00:00 2001 From: Ahmet Oeztuerk Date: Mon, 2 Mar 2026 14:20:34 +0100 Subject: [PATCH 6/6] linter fixes --- pkg/snclient/task_check_system_windows.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkg/snclient/task_check_system_windows.go b/pkg/snclient/task_check_system_windows.go index 93683dad..663b3bcf 100644 --- a/pkg/snclient/task_check_system_windows.go +++ b/pkg/snclient/task_check_system_windows.go @@ -98,6 +98,7 @@ func getPerformanceFrequency() (performanceFrequency uint64) { if returnValue == 0 { taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, "Could not get performance counter frequency") + return 0 } @@ -298,8 +299,9 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { for letter, sdn := range storageDeviceNumbers { // real physical drives seem to have the first 32 deviceNumbers reserved for them if sdn.DeviceNumber > 32 { - taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, fmt.Sprintf("Device unfit to watch, is likely not a drive due to high deviceNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Device unfit to watch, is likely not a drive due to high deviceNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) continue } @@ -308,8 +310,9 @@ func getStorageDeviceNumbersToWatch() map[string]storageDeviceNumberStruct { // for example a CD drive looked like this: // storageDeviceNumber.DeviceNumber = 0 and storageDeviceNumber.PartitionNumber = 4294967295 if sdn.PartitionNumber > 32 { - taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, fmt.Sprintf("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", - letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) + taskCheckSystemInitLogs = append(taskCheckSystemInitLogs, + fmt.Sprintf("Device unfit to watch, is likely not a drive due to high partitionNumber. Letter: %s, DeviceNumber: %d, DeviceType: %d, Partition Number: %d", + letter, sdn.DeviceNumber, sdn.DeviceType, sdn.PartitionNumber)) continue }