155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
package main
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
PathProcPCI = iota
|
|
PathProcUSB
|
|
)
|
|
|
|
func (i *iface) ProcLoc() (err error) {
|
|
spath := strings.Join([]string{i.netpath, "device"}, "/")
|
|
|
|
var real string
|
|
if real, err = filepath.EvalSymlinks(spath); err != nil {
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
err = fmt.Errorf("Interface %s isn't a hardware device", i.names[IfNameKern])
|
|
return
|
|
}
|
|
err = fmt.Errorf("Failed to resolve symlink to device: %w", err)
|
|
return
|
|
}
|
|
|
|
var devpath string
|
|
var ok bool
|
|
|
|
sysdev := strings.Join([]string{SYSFS, "devices/"}, "/")
|
|
if devpath, ok = strings.CutPrefix(real, sysdev); !ok {
|
|
err = fmt.Errorf("Symlink doesn't point to %s\n", sysdev)
|
|
return
|
|
}
|
|
|
|
var (
|
|
pci, usb string
|
|
procmode int
|
|
path = strings.Split(devpath, "/")
|
|
|
|
cdir = strings.Join([]string{
|
|
SYSFS,
|
|
"devices",
|
|
}, "/")
|
|
)
|
|
for i, v := range path {
|
|
if i >= 1 {
|
|
// Append to currend directory
|
|
cdir = strings.Join([]string{cdir, path[i-1]}, "/")
|
|
}
|
|
|
|
if strings.HasPrefix(v, "pci") {
|
|
procmode = PathProcPCI
|
|
continue
|
|
} else if strings.HasPrefix(v, "usb") {
|
|
procmode = PathProcUSB
|
|
continue
|
|
}
|
|
|
|
switch procmode {
|
|
case PathProcPCI:
|
|
{
|
|
var (
|
|
domain, bus, device, function int
|
|
)
|
|
if _, err = fmt.Sscanf(v, "%x:%x:%x.%x", &domain, &bus, &device, &function); err != nil {
|
|
err = ErrInvalidPCIFormat
|
|
continue
|
|
}
|
|
var name strings.Builder
|
|
if domain != 0 {
|
|
// Hey, if you're reading this you're cool.
|
|
// Do you know any machine which has a PCI domain other than 0?
|
|
// Mail me at caskd@redxen.eu about it.
|
|
name.WriteString(fmt.Sprintf("P%d", domain))
|
|
}
|
|
name.WriteString(fmt.Sprintf("p%ds%d", bus, device))
|
|
|
|
// List PCI path to see if there's any other functions available under the same device
|
|
var matches []string
|
|
dir := os.DirFS(cdir)
|
|
glob := fmt.Sprintf("%04x:%02x:%02x.?", domain, bus, device)
|
|
matches, _ = fs.Glob(dir, glob)
|
|
if len(matches) > 1 {
|
|
// Multi-function device
|
|
name.WriteString(fmt.Sprintf("f%d", function))
|
|
}
|
|
|
|
pci = name.String()
|
|
}
|
|
case PathProcUSB:
|
|
{
|
|
var (
|
|
bus, conf, iface int
|
|
port_path []int
|
|
work string
|
|
)
|
|
|
|
res := strings.Split(v, ":")
|
|
if len(res) != 2 {
|
|
err = ErrInvalidUSBFormat
|
|
continue
|
|
}
|
|
|
|
// Bus and ports
|
|
if _, err = fmt.Sscanf(res[0], "%d-%s", &bus, &work); err != nil {
|
|
err = ErrInvalidUSBFormat
|
|
continue
|
|
}
|
|
|
|
for _, v := range strings.Split(work, ".") {
|
|
var cp int
|
|
if _, err = fmt.Sscanf(v, "%d", &cp); err != nil {
|
|
err = ErrInvalidUSBFormat
|
|
continue
|
|
}
|
|
port_path = append(port_path, cp)
|
|
}
|
|
|
|
// Configuration and interface
|
|
if _, err = fmt.Sscanf(res[1], "%d.%d", &conf, &iface); err != nil {
|
|
err = ErrInvalidUSBFormat
|
|
continue
|
|
}
|
|
|
|
var name strings.Builder
|
|
for _, v := range port_path {
|
|
name.WriteString(fmt.Sprintf("u%d", v))
|
|
}
|
|
if conf != 1 {
|
|
name.WriteString(fmt.Sprintf("c%d", conf))
|
|
}
|
|
if iface != 0 {
|
|
name.WriteString(fmt.Sprintf("i%d", iface))
|
|
}
|
|
usb = name.String()
|
|
}
|
|
}
|
|
}
|
|
|
|
// Discard path errors if something was found
|
|
if pci != "" && errors.Is(err, ErrInvalidPCIFormat) {
|
|
err = nil
|
|
}
|
|
if usb != "" && errors.Is(err, ErrInvalidUSBFormat) {
|
|
err = nil
|
|
}
|
|
|
|
i.names[IfNameLoc] = strings.Join([]string{i.pfx, pci, usb}, "")
|
|
return
|
|
}
|