mirror of
https://github.com/prometheus-community/windows_exporter.git
synced 2026-02-25 14:16:36 +00:00
logical_disk: fix volume access with limited permission (#1786)
Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
This commit is contained in:
@@ -17,6 +17,7 @@ package logical_disk
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -312,12 +313,17 @@ func (c *Collector) Collect(ch chan<- prometheus.Metric) error {
|
|||||||
return fmt.Errorf("failed to collect LogicalDisk metrics: %w", err)
|
return fmt.Errorf("failed to collect LogicalDisk metrics: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volumes, err := getAllMountedVolumes()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get volumes: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
for name, volume := range perfData {
|
for name, volume := range perfData {
|
||||||
if c.config.VolumeExclude.MatchString(name) || !c.config.VolumeInclude.MatchString(name) {
|
if c.config.VolumeExclude.MatchString(name) || !c.config.VolumeInclude.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err = getVolumeInfo(name)
|
info, err = getVolumeInfo(volumes, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Warn("failed to get volume information for "+name,
|
c.logger.Warn("failed to get volume information for "+name,
|
||||||
slog.Any("err", err),
|
slog.Any("err", err),
|
||||||
@@ -477,34 +483,15 @@ func getDriveType(driveType uint32) string {
|
|||||||
const diskExtentSize = 24
|
const diskExtentSize = 24
|
||||||
|
|
||||||
// getDiskIDByVolume returns the disk ID for a given volume.
|
// getDiskIDByVolume returns the disk ID for a given volume.
|
||||||
func getVolumeInfo(rootDrive string) (volumeInfo, error) {
|
func getVolumeInfo(volumes map[string]string, rootDrive string) (volumeInfo, error) {
|
||||||
volumePath := rootDrive
|
volumePath := rootDrive
|
||||||
|
|
||||||
// If rootDrive is a NTFS directory, convert it to a volume GUID.
|
// If rootDrive is a NTFS directory, convert it to a volume GUID.
|
||||||
if strings.Contains(volumePath, `\`) {
|
if volumeGUID, ok := volumes[rootDrive]; ok {
|
||||||
// GetVolumeNameForVolumeMountPoint expects a trailing backslash.
|
|
||||||
volumePath += `\`
|
|
||||||
|
|
||||||
volumePathName, err := windows.UTF16PtrFromString(volumePath)
|
|
||||||
if err != nil {
|
|
||||||
return volumeInfo{}, fmt.Errorf("could not convert rootDrive to volume path %s: %w", volumePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
volumeGUIDPtr := make([]uint16, 50)
|
|
||||||
if err := windows.GetVolumeNameForVolumeMountPoint(volumePathName, &volumeGUIDPtr[0], uint32(len(volumeGUIDPtr))); err != nil {
|
|
||||||
return volumeInfo{}, fmt.Errorf("could not get volume GUID for volume %s: %w", volumePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
volumePath = windows.UTF16ToString(volumeGUIDPtr)
|
|
||||||
|
|
||||||
// GetVolumeNameForVolumeMountPoint returns the volume GUID path as \\?\Volume{GUID}\
|
// GetVolumeNameForVolumeMountPoint returns the volume GUID path as \\?\Volume{GUID}\
|
||||||
// According https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol#remarks
|
// According https://learn.microsoft.com/en-us/windows/win32/api/ioapiset/nf-ioapiset-deviceiocontrol#remarks
|
||||||
// Win32 Drive Namespace is prefixed with \\.\, so we need to remove the \\?\ prefix.
|
// Win32 Drive Namespace is prefixed with \\.\, so we need to remove the \\?\ prefix.
|
||||||
volumePath, _ = strings.CutPrefix(volumePath, `\\?\`)
|
volumePath, _ = strings.CutPrefix(volumeGUID, `\\?\`)
|
||||||
|
|
||||||
// https://stackoverflow.com/questions/55710326/how-to-get-the-physical-device-that-a-volume-guid-path-belongs-to#comment98104360_55710326
|
|
||||||
// DeviceIoControl expects no trailing backslash in the volume GUID path.
|
|
||||||
volumePath = strings.TrimRight(volumePath, `\`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
volumePathPtr := windows.StringToUTF16Ptr(`\\.\` + volumePath)
|
volumePathPtr := windows.StringToUTF16Ptr(`\\.\` + volumePath)
|
||||||
@@ -581,3 +568,59 @@ func getVolumeInfo(rootDrive string) (volumeInfo, error) {
|
|||||||
readonly: float64(fsFlags & windows.FILE_READ_ONLY_VOLUME),
|
readonly: float64(fsFlags & windows.FILE_READ_ONLY_VOLUME),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAllMountedVolumes() (map[string]string, error) {
|
||||||
|
guidBuf := make([]uint16, windows.MAX_PATH+1)
|
||||||
|
guidBufLen := uint32(len(guidBuf) * 2)
|
||||||
|
|
||||||
|
hFindVolume, err := windows.FindFirstVolume(&guidBuf[0], guidBufLen)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("FindFirstVolume: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
_ = windows.FindVolumeClose(hFindVolume)
|
||||||
|
}()
|
||||||
|
|
||||||
|
volumes := map[string]string{}
|
||||||
|
|
||||||
|
for ; ; err = windows.FindNextVolume(hFindVolume, &guidBuf[0], guidBufLen) {
|
||||||
|
if err != nil {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, windows.ERROR_NO_MORE_FILES):
|
||||||
|
return volumes, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("FindNextVolume: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rootPathLen uint32
|
||||||
|
|
||||||
|
rootPathBuf := make([]uint16, windows.MAX_PATH+1)
|
||||||
|
rootPathBufLen := uint32(len(rootPathBuf) * 2)
|
||||||
|
|
||||||
|
for {
|
||||||
|
err = windows.GetVolumePathNamesForVolumeName(&guidBuf[0], &rootPathBuf[0], rootPathBufLen, &rootPathLen)
|
||||||
|
if err == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if errors.Is(err, windows.ERROR_NO_MORE_FILES) {
|
||||||
|
rootPathBuf = make([]uint16, (rootPathLen+1)/2)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("GetVolumePathNamesForVolumeName: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mountPoint := windows.UTF16ToString(rootPathBuf)
|
||||||
|
|
||||||
|
// Skip unmounted volumes
|
||||||
|
if len(mountPoint) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
volumes[strings.TrimSuffix(mountPoint, `\`)] = strings.TrimSuffix(windows.UTF16ToString(guidBuf), `\`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user