1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
|
package utils
import (
"fmt"
"io/ioutil"
"os/exec"
"strings"
)
// UEventType device port r=type
type UEventType int
const (
// device with pci port
UEventTypePCI UEventType = iota + 11
// device with usb port
UEventTypeUSB
)
const (
// SlotTypePCI pci type slot
SlotTypePCI = "pci"
// SlotTypeUSB usb type slot
SlotTypeUSB = "usb"
)
// IDInfo store device vendor or device info
type IDInfo struct {
ID string
Name string
}
// PCIUevent pci uevent data
type PCIUEvent struct {
Driver string
Vendor *IDInfo
Device *IDInfo
SVendor *IDInfo // subsystem vendor
SDevice *IDInfo // subsystem device
name string
slotName string
}
// USBUEvent usb uevent data
type USBUEvent struct {
Driver string
Vendor string
Product string
name string
}
// UEvent store device uevent file
type UEvent struct {
Type UEventType
Name string
Data interface{}
}
func NewUEvent(filename string) (*UEvent, error) {
contents, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var pairs = make(map[string]string)
lines := strings.Split(string(contents), "\n")
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.SplitN(line, "=", 2)
pairs[items[0]] = items[1]
}
var info UEvent
if _, ok := pairs["PCI_SLOT_NAME"]; ok {
info.Type = UEventTypePCI
var pci *PCIUEvent
pci, err = newPCIUEvent(pairs)
if err == nil {
info.Name = pci.name
info.Data = pci
}
} else {
var usb *USBUEvent
info.Type = UEventTypeUSB
usb, err = newUSBUEvent(pairs)
if err == nil {
info.Name = usb.name
info.Data = usb
}
}
if err != nil {
return nil, err
}
return &info, nil
}
func newPCIUEvent(pairs map[string]string) (*PCIUEvent, error) {
var info = PCIUEvent{
Driver: pairs["DRIVER"],
slotName: pairs["PCI_SLOT_NAME"],
}
output, err := getCommandOutput(fmt.Sprintf("lspci -vmm -s %s", info.slotName))
if err != nil {
return nil, err
}
outPairs := formatLspciOutput(output)
pciID := pairs["PCI_ID"]
idItems := strings.Split(pciID, ":")
info.Vendor = &IDInfo{ID: idItems[0], Name: outPairs["Vendor"]}
info.Device = &IDInfo{ID: idItems[1], Name: outPairs["Device"]}
subsysID := pairs["PCI_SUBSYS_ID"]
subsysItems := strings.Split(subsysID, ":")
info.SVendor = &IDInfo{ID: subsysItems[0], Name: outPairs["SVendor"]}
info.SDevice = &IDInfo{ID: subsysItems[1], Name: outPairs["SDevice"]}
info.name = fmt.Sprintf("%s %s", info.Vendor.Name, info.Device.Name)
return &info, nil
}
func newUSBUEvent(pairs map[string]string) (*USBUEvent, error) {
var info = USBUEvent{
Driver: pairs["DRIVER"],
}
product := pairs["PRODUCT"]
items := strings.Split(product, "/")
if len(items) < 3 {
return nil, fmt.Errorf("invalid uevent format, items < 3")
}
// compatible usb mouse
idx := 0
if len(items) == 4 {
idx = 1
}
info.Vendor = fmt.Sprintf("%04s", items[idx])
info.Product = fmt.Sprintf("%04s", items[idx+1])
output, err := getCommandOutput(fmt.Sprintf("lsusb -d %s:%s",
info.Vendor, info.Product))
if err != nil {
return nil, err
}
info.name = formatLsusbOutput(output)
return &info, nil
}
func formatLspciOutput(output []byte) map[string]string {
lines := strings.Split(string(output), "\n")
var pairs = make(map[string]string)
for _, line := range lines {
if len(line) == 0 {
continue
}
items := strings.SplitN(line, ":", 2)
items[1] = strings.TrimSpace(items[1])
pairs[items[0]] = items[1]
}
return pairs
}
func formatLsusbOutput(output []byte) string {
line := string(output)
line = strings.TrimRight(line, "\n")
items := strings.Split(line, "ID ")
list := strings.SplitN(items[1], " ", 2)
if len(list) != 2 {
return ""
}
return list[1]
}
func getCommandOutput(cmd string) ([]byte, error) {
return exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
}
|