Skip to content

Commit

Permalink
net_class: catch syscall.EINVAL and better handle read errors
Browse files Browse the repository at this point in the history
prometheus#483 introduced a bug
that terminates attribute reading when the returned error is
syscall.Errno, which is what util.SysReadFile() will typically
return. Handle that case specifically.

While doing that pull the error checking into
ParseNetClassAttribute() for clarity and to allow external
callers to handle errors correctly.

Signed-off-by: Dan Williams <dcbw@redhat.com>
  • Loading branch information
dcbw committed May 10, 2023
1 parent 718836a commit b46febd
Showing 1 changed file with 25 additions and 8 deletions.
33 changes: 25 additions & 8 deletions sysfs/net_class.go
Expand Up @@ -117,14 +117,35 @@ func (fs FS) NetClass() (NetClass, error) {
return netClass, nil
}

// isFatalError returns true if the error should terminate attribute reading
func isFatalError(err error) bool {
var errno syscall.Errno

if os.IsNotExist(err) {
return false
} else if os.IsPermission(err) {
return false
} else if err.Error() == "operation not supported" {
return false
} else if errors.Is(err, os.ErrInvalid) {
return false
} else if errors.As(err, &errno) && (errno == syscall.EINVAL) {
return false
}
return true
}

// ParseNetClassAttribute parses a given file in /sys/class/net/<iface>
// and sets the value in a given NetClassIface object if the value was readable.
// It returns an error if the file cannot be read.
// It returns an error if the file cannot be read and the error is fatal.
func ParseNetClassAttribute(devicePath, attrName string, interfaceClass *NetClassIface) error {
attrPath := filepath.Join(devicePath, attrName)
value, err := util.SysReadFile(attrPath)
if err != nil {
return fmt.Errorf("failed to read file %q: %w", attrPath, err)
if isFatalError(err) {
return fmt.Errorf("failed to read file %q: %w", attrPath, err)
}
return nil
}

vp := util.NewValueParser(value)
Expand Down Expand Up @@ -202,12 +223,8 @@ func parseNetClassIface(devicePath string) (*NetClassIface, error) {
if !f.Type().IsRegular() {
continue
}
err := ParseNetClassAttribute(devicePath, f.Name(), &interfaceClass)
if err != nil {
// Return fatal errors to caller
if !os.IsNotExist(err) && !os.IsPermission(err) && err.Error() != "operation not supported" && !errors.Is(err, os.ErrInvalid) {
return nil, err
}
if err := ParseNetClassAttribute(devicePath, f.Name(), &interfaceClass); err != nil {
return nil, err
}
}

Expand Down

0 comments on commit b46febd

Please sign in to comment.