pax_global_header00006660000000000000000000000064140730067270014520gustar00rootroot0000000000000052 comment=e1f3df0f4493f6f6ace573b96bc271f562c3fa92 hardware-0.1.8/000077500000000000000000000000001407300672700133235ustar00rootroot00000000000000hardware-0.1.8/LICENSE000066400000000000000000000021211407300672700143240ustar00rootroot00000000000000The MIT License (MIT) Copyright (c) 2019-NOW jouyouyun Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. hardware-0.1.8/README.org000066400000000000000000000005731407300672700147760ustar00rootroot00000000000000#+OPTIONS: toc:nil num:nil timestamp:nil #+AUTHOR: jouyouyun #+TITLE: Hardware Info Library For Linux Supported the following hardware info: + [x] cpu + [ ] memory + [x] dmi + [x] disk + [x] graphic + [x] network + [x] sound + [x] peripherals + [x] backlight + [x] bluetooth + [x] camera + [x] battery Contains every device name, vendor, product etc. hardware-0.1.8/battery/000077500000000000000000000000001407300672700147755ustar00rootroot00000000000000hardware-0.1.8/battery/battery.go000066400000000000000000000041411407300672700167760ustar00rootroot00000000000000package battery import ( "io/ioutil" "path/filepath" "strconv" "strings" "github.com/jouyouyun/hardware/utils" ) const ( batterySysfsDir = "/sys/class/power_supply" ) // Battery store battery info type Battery struct { Name string Model string Manufacturer string Serial string Technology string CapacityDesign int64 CapacityNow int64 } // BatteryList store battery list type BatteryList []*Battery // GetBatteryList return battery list func GetBatteryList() (BatteryList, error) { list, err := utils.ScanDir(batterySysfsDir, func(string) bool { return false }) if err != nil { return nil, err } var batList BatteryList for _, name := range list { if !isBattery(batterySysfsDir, name) { continue } bat, err := newBattery(batterySysfsDir, name) if err != nil { return nil, err } batList = append(batList, bat) } return batList, nil } func newBattery(dir, name string) (*Battery, error) { uevent := filepath.Join(dir, name, "uevent") set, err := parseFile(uevent) if err != nil { return nil, err } var bat = Battery{ Name: set["POWER_SUPPLY_NAME"], Model: set["POWER_SUPPLY_MODEL_NAME"], Manufacturer: set["POWER_SUPPLY_MANUFACTURER"], Serial: set["POWER_SUPPLY_SERIAL_NUMBER"], Technology: set["POWER_SUPPLY_TECHNOLOGY"], } bat.CapacityDesign, _ = strconv.ParseInt(set["POWER_SUPPLY_CHARGE_FULL_DESIGN"], 10, 64) bat.CapacityNow, _ = strconv.ParseInt(set["POWER_SUPPLY_CHARGE_NOW"], 10, 64) return &bat, nil } func isBattery(dir, name string) bool { filename := filepath.Join(dir, name, "type") ty, err := utils.ReadFileContent(filename) if err != nil { return false } return ty == "Battery" } func parseFile(filename string) (map[string]string, error) { content, err := ioutil.ReadFile(filename) if err != nil { return nil, err } var set = make(map[string]string) lines := strings.Split(string(content), "\n") for _, line := range lines { if len(line) == 0 { continue } items := strings.Split(line, "=") if len(items) != 2 { continue } set[items[0]] = items[1] } return set, nil } hardware-0.1.8/bluetooth/000077500000000000000000000000001407300672700153305ustar00rootroot00000000000000hardware-0.1.8/bluetooth/bluetooth.go000066400000000000000000000015411407300672700176650ustar00rootroot00000000000000package bluetooth import ( "github.com/jouyouyun/hardware/utils" ) const ( blueSysfsDir = "/sys/class/bluetooth" ) // Bluetooth store bluetooth info type Bluetooth struct { utils.CardInfo } // BluetoothList store bluetooth list type BluetoothList []*Bluetooth // GetBluetoothList return bluetooth device list func GetBluetoothList() (BluetoothList, error) { list, err := utils.ScanDir(blueSysfsDir, utils.FilterBluetoothName) if err != nil { return nil, err } var blueList BluetoothList for _, name := range list { blue, err := newBluetooth(blueSysfsDir, name) if err != nil { return nil, err } blueList = append(blueList, blue) } return blueList, nil } func newBluetooth(dir, name string) (*Bluetooth, error) { card, err := utils.NewCardInfo(dir, name) if err != nil { return nil, err } return &Bluetooth{CardInfo: *card}, nil } hardware-0.1.8/camera/000077500000000000000000000000001407300672700145535ustar00rootroot00000000000000hardware-0.1.8/camera/camera.go000066400000000000000000000023601407300672700163330ustar00rootroot00000000000000package camera import ( "github.com/jouyouyun/hardware/utils" ) const ( cameraSysfsDir = "/sys/class/video4linux" ) // Camera store camera device info type Camera struct { utils.CardInfo } // CameraList store camera device list type CameraList []*Camera // GetCameraList return camera device list func GetCameraList() (CameraList, error) { list, err := utils.ScanDir(cameraSysfsDir, utils.FilterCameraName) if err != nil { return nil, err } var cards CameraList for _, name := range list { card, err := newCamera(cameraSysfsDir, name) if err != nil { return nil, err } cards = cards.Append(card) } return cards, nil } func newCamera(dir, name string) (*Camera, error) { card, err := utils.NewCardInfo(cameraSysfsDir, name) if err != nil { return nil, err } return &Camera{CardInfo: *card}, nil } // Append append camera device after filter duplication device // In X230 has two same camera device func (list CameraList) Append(card *Camera) CameraList { for _, v := range list { if v.Equal(card) { return list } } list = append(list, card) return list } // Equal check device whether equal by vendor and product func (c *Camera) Equal(tmp *Camera) bool { return c.Vendor == tmp.Vendor && c.Product == tmp.Product } hardware-0.1.8/cpu/000077500000000000000000000000001407300672700141125ustar00rootroot00000000000000hardware-0.1.8/cpu/cpu.go000066400000000000000000000037261407300672700152400ustar00rootroot00000000000000package cpu import ( "strconv" "github.com/jouyouyun/hardware/utils" ) const ( cpuKeyName = "model name" cpuKeyCores = "cpu cores" cpuKeyModel = "cpu model" // for sw and loonson cpuKeyCPUs = "cpus detected" // for sw cpuKeyProcessor = "processor" // for loonson and arm cpuKeyNameARM = "Processor" // for arm cpuKeyDelim = ":" cpuFilename = "/proc/cpuinfo" ) var ( _cpu *CPU ) // CPU store cpu info type CPU struct { Name string Processors int } // NewCPU return cpu name and processor number func NewCPU() (*CPU, error) { if _cpu != nil { return _cpu, nil } cpu, err := newCPU(cpuFilename) if err == nil { _cpu = cpu return cpu, nil } cpu, err = newCPUForSW(cpuFilename) if err == nil { _cpu = cpu return cpu, nil } cpu, err = newCPUForLoonson(cpuFilename) if err == nil { _cpu = cpu return cpu, nil } cpu, err = newCPUForARM(cpuFilename) if err == nil { _cpu = cpu return cpu, nil } return nil, err } func newCPU(filename string) (*CPU, error) { return doNewCPU(filename, []string{ cpuKeyName, cpuKeyCores, }, false, false) } func newCPUForSW(filename string) (*CPU, error) { return doNewCPU(filename, []string{ cpuKeyModel, cpuKeyCPUs, }, false, false) } func newCPUForLoonson(filename string) (*CPU, error) { return doNewCPU(filename, []string{ cpuKeyModel, cpuKeyProcessor, }, true, true) } func newCPUForARM(filename string) (*CPU, error) { return doNewCPU(filename, []string{ cpuKeyNameARM, cpuKeyProcessor, }, true, true) } func doNewCPU(filename string, keys []string, fall, numIncr bool) (*CPU, error) { var keySet = make(map[string]string) for _, key := range keys { keySet[key] = "" } err := utils.ProcGetByKey(filename, cpuKeyDelim, keySet, fall) if err != nil { return nil, err } num, err := strconv.Atoi(keySet[keys[1]]) if err != nil { return nil, err } if numIncr { num++ } return &CPU{ Name: keySet[keys[0]], Processors: num, }, nil } hardware-0.1.8/cpu/cpu_test.go000066400000000000000000000035541407300672700162760ustar00rootroot00000000000000package cpu import ( "testing" ) func TestNewCPU(t *testing.T) { cpu, err := newCPU("./testdata/cpuinfo") if err != nil { t.Fatalf("get cpu info error,%v", err) } c1 := &CPU{ Name: "Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz", Processors: 2, } if cpu.Name != c1.Name { t.Errorf("cpu name test failed: excepted %s, but got %s", c1.Name, cpu.Name) } if cpu.Processors != c1.Processors { t.Errorf("cpu processor test failed: excepted %d, but got %d", c1.Processors, cpu.Processors) } swCpu, err := newCPUForSW("./testdata/swinfo") if err != nil { t.Fatalf("get sw cpu info error,%v", err) } c2 := &CPU{ Name: "sw", Processors: 4, } if swCpu.Name != c2.Name { t.Errorf("SW cpu name test failed: excepted %s, but got %s", c2.Name, swCpu.Name) } if swCpu.Processors != c2.Processors { t.Errorf("SW cpu processor test failed: excepted %d, but got %d", c2.Processors, swCpu.Processors) } armCpu, err := newCPUForARM("./testdata/arminfo") if err != nil { t.Fatalf("get arm cpu info error,%v", err) } c3 := &CPU{ Name: "ARMv7 Processor rev 0 (v7l)", Processors: 4, } if armCpu.Name != c3.Name { t.Errorf("ARM cpu name test failed: excepted %s, but got %s", c3.Name, armCpu.Name) } if armCpu.Processors != c3.Processors { t.Errorf("ARM cpu processor test failed: excepted %d, but got %d", c3.Processors, armCpu.Processors) } loonsonCpu, err := newCPUForLoonson("./testdata/loonsoninfo") if err != nil { t.Fatalf("get loonson cpu info error,%v", err) } c4 := &CPU{ Name: "Loongson-3B V0.7 FPU V0.1", Processors: 6, } if loonsonCpu.Name != c4.Name { t.Errorf("LOONSON cpu name test failed: excepted %s, but got %s", c3.Name, loonsonCpu.Name) } if loonsonCpu.Processors != c4.Processors { t.Errorf("LOONSON cpu processor test failed: excepted %d, but got %d", c3.Processors, loonsonCpu.Processors) } } hardware-0.1.8/cpu/testdata/000077500000000000000000000000001407300672700157235ustar00rootroot00000000000000hardware-0.1.8/cpu/testdata/arminfo000066400000000000000000000006101407300672700172760ustar00rootroot00000000000000Processor : ARMv7 Processor rev 0 (v7l) processor : 0 BogoMIPS : 2390.01 processor : 1 BogoMIPS : 2390.01 processor : 2 BogoMIPS : 2390.01 processor : 3 BogoMIPS : 2390.01 Features : swp half thumb fastmult vfp edsp neon vfpv3 tls CPU implementer : 0x41 CPU architecture: 7 CPU variant : 0x3 CPU part : 0xc09 CPU revision : 0 Hardware : NANOPI2 Revision : 0000 Serial : fa4418dba4420544hardware-0.1.8/cpu/testdata/cpuinfo000066400000000000000000000064721407300672700173220ustar00rootroot00000000000000processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 37 model name : Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz stepping : 2 microcode : 0x9 cpu MHz : 1066.000 cache size : 3072 KB physical id : 0 siblings : 4 core id : 0 cpu cores : 2 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat dtherm tpr_shadow vnmi flexpriority ept vpid bugs : bogomips : 4255.61 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 1 vendor_id : GenuineIntel cpu family : 6 model : 37 model name : Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz stepping : 2 microcode : 0x9 cpu MHz : 1066.000 cache size : 3072 KB physical id : 0 siblings : 4 core id : 2 cpu cores : 2 apicid : 4 initial apicid : 4 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat dtherm tpr_shadow vnmi flexpriority ept vpid bugs : bogomips : 4255.61 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 2 vendor_id : GenuineIntel cpu family : 6 model : 37 model name : Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz stepping : 2 microcode : 0x9 cpu MHz : 933.000 cache size : 3072 KB physical id : 0 siblings : 4 core id : 0 cpu cores : 2 apicid : 1 initial apicid : 1 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat dtherm tpr_shadow vnmi flexpriority ept vpid bugs : bogomips : 4255.61 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: processor : 3 vendor_id : GenuineIntel cpu family : 6 model : 37 model name : Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz stepping : 2 microcode : 0x9 cpu MHz : 1066.000 cache size : 3072 KB physical id : 0 siblings : 4 core id : 2 cpu cores : 2 apicid : 5 initial apicid : 5 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm sse4_1 sse4_2 popcnt lahf_lm arat dtherm tpr_shadow vnmi flexpriority ept vpid bugs : bogomips : 4255.61 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: hardware-0.1.8/cpu/testdata/loonsoninfo000066400000000000000000000045351407300672700202200ustar00rootroot00000000000000system type : lst-loongson3-eva machine : Unknown processor : 0 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 1 VCED exceptions : not available VCEI exceptions : not available processor : 1 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 2 VCED exceptions : not available VCEI exceptions : not available processor : 2 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 3 VCED exceptions : not available VCEI exceptions : not available processor : 3 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 5 VCED exceptions : not available VCEI exceptions : not available processor : 4 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 6 VCED exceptions : not available VCEI exceptions : not available processor : 5 cpu model : Loongson-3B V0.7 FPU V0.1 BogoMIPS : 874.96 cpu MHz : 1093.70 wait instruction : no microsecond timers : yes tlb_entries : 64 extra interrupt vector : no hardware watchpoint : yes, count: 0, address/irw mask: [] ASEs implemented : shadow register sets : 1 kscratch registers : 0 core : 7 VCED exceptions : not available VCEI exceptions : not availablehardware-0.1.8/cpu/testdata/swinfo000066400000000000000000000013501407300672700171520ustar00rootroot00000000000000cpu : sw cpu model : sw cpu variation : 1 cpu revision : 0 cpu serial number : system type : Tembin system variation : Tembin system revision : 0 system serial number : 30303030 CPU frequency [MHz] : 1400.00 timer frequency [Hz] : 1024.00 page size [bytes] : 8192 phys. address bits : 40 max. addr. space # : 255 BogoMIPS : 2791.42 kernel unaligned acc : 1480274 (pc=fffffc0000ee8460,va=fffffc00d971c89e) user unaligned acc : 1805698 (pc=200007629a4,va=11feb9264) platform string : Unknown manufacturer. cpus detected : 4 cpus active : 4 cpu active mask : 000000000000000f cpus core_start : 000000000000000f L1 Icache : 128K, 2-way, 128b line L1 Dcache : 128K, 4-way, 128b line L2 cache : 2048K, 8-way, 128b line L3 cache : n/ahardware-0.1.8/disk/000077500000000000000000000000001407300672700142555ustar00rootroot00000000000000hardware-0.1.8/disk/disk.go000066400000000000000000000056511407300672700155450ustar00rootroot00000000000000package disk import ( "encoding/json" "os/exec" "strconv" "strings" "github.com/jouyouyun/hardware/utils" ) const ( uuidDelim = "+" ) // Disk store disk info type Disk struct { Name string Model string Serial string // if empty, use children uuid's sha256 replace Vendor string Size int64 // byte RootMounted bool } // DiskList multi disk type DiskList []*Disk type lsblkDevice struct { Name string `json:"name"` Serial string `json:"serial"` Type string `json:"type"` Vendor string `json:"vendor"` Model string `json:"model"` UUID string `json:"uuid"` MountPoint string `json:"mountpoint"` Size interface{} `json:"size"` Children lsblkDeviceList `json:"children"` } type lsblkDeviceList []*lsblkDevice type lsblkOutput struct { Blockdevices lsblkDeviceList `json:"blockdevices"` } func GetDiskList() (DiskList, error) { out, err := execLsblk() if err != nil { return nil, err } return newDiskListFromOutput(out) } func (list DiskList) GetRoot() *Disk { for _, d := range list { if d.RootMounted { return d } } return nil } func newDiskListFromOutput(out []byte) (DiskList, error) { lsblk, err := parseLsblkOutput(out) if err != nil { return nil, err } var disks DiskList for _, info := range lsblk.Blockdevices { disks = append(disks, newDiskFromDevice(info)) } return disks, nil } func newDiskFromDevice(dev *lsblkDevice) *Disk { var info = Disk{ Name: dev.Name, Model: dev.Model, Serial: dev.Serial, Vendor: dev.Vendor, RootMounted: dev.RootMounted(), } if v, ok := dev.Size.(string); ok { info.Size, _ = strconv.ParseInt(v, 10, 64) } else if v, ok := dev.Size.(float64); ok { info.Size = int64(v) } if len(info.Serial) == 0 { // using children uuid list's sha256 as serial info.Serial = genSerialByUUIDList(dev.GetUUIDList()) } return &info } func genSerialByUUIDList(list []string) string { if len(list) == 0 { return "" } str := strings.Join(list, uuidDelim) return utils.SHA256Sum([]byte(str)) } func (dev *lsblkDevice) RootMounted() bool { if dev.MountPoint == "/" { return true } return FoundMountPoint(dev.Children) } func FoundMountPoint(childrens lsblkDeviceList) bool { for _, child := range childrens { if child.MountPoint == "/" { return true } if len(child.Children) != 0 { return FoundMountPoint(child.Children) } } return false } func (dev *lsblkDevice) GetUUIDList() []string { var list []string for _, child := range dev.Children { if len(child.UUID) == 0 { continue } list = append(list, child.UUID) } return list } func parseLsblkOutput(out []byte) (*lsblkOutput, error) { var info lsblkOutput err := json.Unmarshal(out, &info) if err != nil { return nil, err } return &info, nil } func execLsblk() ([]byte, error) { lsblk := "lsblk -J -bno NAME,SERIAL,TYPE,SIZE,VENDOR,MODEL,MOUNTPOINT,UUID" return exec.Command("/bin/sh", "-c", lsblk).CombinedOutput() } hardware-0.1.8/disk/disk_test.go000066400000000000000000000055231407300672700166020ustar00rootroot00000000000000package disk import ( "testing" ) func TestGetRootMountInfo(t *testing.T) { var str = `{ "blockdevices": [ {"name":"sdb", "serial":"68f9ds8fd7f8d52c8a2dj78fg79ss9c", "type":"disk", "size":15548554655, "vendor":"VMware, ", "model":"VMware_Virtual_S", "mountpoint":null, "uuid":null, "children": [ {"name":"sda1", "serial":null, "type":"part", "size":1610612736, "vendor":null, "model":null, "mountpoint":"/", "uuid":"c41673e5-638f-4f3c-b52d-cd1667e024b3"}, {"name":"sda3", "serial":null, "type":"part", "size":2147483648, "vendor":null, "model":null, "mountpoint":"[SWAP]", "uuid":"b8604489-15fc-40e8-bd69-74bad4045624", "children": [ {"name":"sda4", "serial":null, "type":"part1", "size":85894356591, "vendor":null, "model":null, "mountpoint":"/bin", "uuid":"dd52f15b-876a-4cb1-8eec-013c974c568a"} ] } ] }, {"name":"zzzz", "serial":"10c34x45c45155d024f55sd4a4ba0001", "type":"rom", "size":2226057216, "vendor":"NECVMWar", "model":"VMware_Virtual_IDE_CDROM_Drive", "mountpoint":"/", "uuid":"2020-01-14-08-15-26-00"}, {"name":"adc", "serial":"10c34x45c45155d024f55sd4a4ba0001", "type":"rom", "size":2226057216, "vendor":"NECVMWar", "model":"VMware_Virtual_IDE_CDROM_Drive", "mountpoint":"/media/kyrie/uos 20", "uuid":"2020-01-14-08-15-26-00"} ] }` disk, err := newDiskListFromOutput([]byte(str)) if err != nil { t.Error("json format error") } var infos = DiskList{ &Disk{ Name: "sdb", Model: "VMware_Virtual_S", Serial: "68f9ds8fd7f8d52c8a2dj78fg79ss9c", Vendor: "VMware, ", Size: 15548554655, RootMounted: true, }, &Disk{ Name: "zzzz", Model: "VMware_Virtual_IDE_CDROM_Drive", Serial: "10c34x45c45155d024f55sd4a4ba0001", Vendor: "NECVMWar", Size: 2226057216, RootMounted: true, }, &Disk{ Name: "adc", Model: "VMware_Virtual_IDE_CDROM_Drive", Serial: "10c34x45c45155d024f55sd4a4ba0001", Vendor: "NECVMWar", Size: 2226057216, RootMounted: false, }, } for i, v := range disk { if v.Name != infos[i].Name { t.Errorf("Disk name test failed: excepted %s, but got %s", infos[i].Name, v.Name) } if v.Model != infos[i].Model { t.Errorf("Disk model test failed: excepted %s, but got %s", infos[i].Model, v.Model) } if v.Vendor != infos[i].Vendor { t.Errorf("Disk vendor test failed: excepted %s, but got %s", infos[i].Vendor, v.Vendor) } if v.Serial != infos[i].Serial { t.Errorf("Disk serial test failed: excepted %s, but got %s", infos[i].Serial, v.Serial) } if v.Size != infos[i].Size { t.Errorf("Disk size test failed: excepted %v, but got %v", infos[i].Size, v.Size) } if v.RootMounted != infos[i].RootMounted { t.Errorf("Disk root mounted test failed: excepted %v, but got %v", infos[i].RootMounted, v.RootMounted) } } } hardware-0.1.8/dmi/000077500000000000000000000000001407300672700140745ustar00rootroot00000000000000hardware-0.1.8/dmi/dmi.go000066400000000000000000000041371407300672700152010ustar00rootroot00000000000000package dmi import ( "fmt" "path/filepath" "encoding/json" "strings" "github.com/jouyouyun/hardware/utils" ) // DMI store bios, board, product info type DMI struct { BiosVendor string `json:"bios_vendor"` BiosVersion string `json:"bios_version"` BiosDate string `json:"bios_date"` BoardName string `json:"board_name"` BoardSerial string `json:"board_serial"` BoardVendor string `json:"board_vendor"` BoardVersion string `json:"board_version"` ProductName string `json:"product_name"` ProductFamily string `json:"product_family"` ProductSerial string `json:"product_serial"` ProductUUID string `json:"product_uuid"` ProductVersion string `json:"product_version"` } const ( dmiDirPrefix = "/sys/class/dmi/id" ) var ( _dmi *DMI ) func (dmi *DMI) IsValid() bool { var keys = []string{ dmi.ProductUUID, dmi.ProductSerial, dmi.ProductFamily, dmi.ProductName, } for _, key := range keys { if !checkValid(key) { return false } } return true } // GetDMI return bios, board, product info func GetDMI() (*DMI, error) { if _dmi == nil { dmi, err := doGetDMI(dmiDirPrefix) if err != nil { return nil, err } _dmi = dmi } return _dmi, nil } func doGetDMI(dir string) (*DMI, error) { var files = []string{ "bios_vendor", "bios_version", "bios_date", "board_name", "board_serial", "board_version", "board_vendor", "product_name", "product_serial", "product_family", "product_uuid", "product_version", } var set = make(map[string]string) for _, key := range files { value, err := utils.ReadFileContent(filepath.Join(dmiDirPrefix, key)) if err != nil { continue } set[key] = value } if len(set) == 0 { return nil, fmt.Errorf("get dmi failure") } data, err := json.Marshal(set) if err != nil { return nil, err } var dmi DMI err = json.Unmarshal(data, &dmi) if err != nil { return nil, err } return &dmi, nil } func checkValid(key string) bool { if len(key) == 0 { return false } tmp := strings.ToLower(key) if tmp == "unknown" || tmp == "none" || tmp == "null" { return false } return true } hardware-0.1.8/examples/000077500000000000000000000000001407300672700151415ustar00rootroot00000000000000hardware-0.1.8/examples/.gitignore000066400000000000000000000000131407300672700171230ustar00rootroot00000000000000/dump /mid hardware-0.1.8/examples/dump.go000066400000000000000000000047311407300672700164420ustar00rootroot00000000000000package main import ( "encoding/json" "fmt" "github.com/jouyouyun/hardware/battery" "github.com/jouyouyun/hardware/bluetooth" "github.com/jouyouyun/hardware/camera" "github.com/jouyouyun/hardware/cpu" "github.com/jouyouyun/hardware/disk" "github.com/jouyouyun/hardware/dmi" "github.com/jouyouyun/hardware/graphic" "github.com/jouyouyun/hardware/memory" "github.com/jouyouyun/hardware/network" "github.com/jouyouyun/hardware/peripherals" "github.com/jouyouyun/hardware/sound" ) func main() { dumpCPU() dumpMemory() dumpDMI() dumpDisk() dumpGraphic() dumpNetwork() dumpSound() dumpPeripherals() dumpBluetooth() dumpBattery() dumpCamera() } func dumpDMI() { doDump("dmi", func() (interface{}, error) { info, err := dmi.GetDMI() return info, err }) } func dumpCPU() { doDump("cpu", func() (interface{}, error) { info, err := cpu.NewCPU() return info, err }) } func dumpBattery() { doDump("battery", func() (interface{}, error) { info, err := battery.GetBatteryList() return info, err }) } func dumpBluetooth() { doDump("bluetooth", func() (interface{}, error) { info, err := bluetooth.GetBluetoothList() return info, err }) } func dumpCamera() { doDump("camera", func() (interface{}, error) { info, err := camera.GetCameraList() return info, err }) } func dumpDisk() { doDump("disk", func() (interface{}, error) { info, err := disk.GetDiskList() return info, err }) } func dumpNetwork() { doDump("network", func() (interface{}, error) { info, err := network.GetNetworkList() return info, err }) } func dumpGraphic() { doDump("graphic", func() (interface{}, error) { info, err := graphic.GetGraphicList() return info, err }) } func dumpMemory() { doDump("memory", func() (interface{}, error) { info, err := memory.GetMemoryList() return info, err }) } func dumpPeripherals() { doDump("peripherals", func() (interface{}, error) { info, err := peripherals.GetPeripheralsList() return info, err }) } func dumpSound() { doDump("sound", func() (interface{}, error) { info, err := sound.GetSoundList() return info, err }) } func doDump(name string, getter func() (interface{}, error)) { fmt.Printf("Dump %s: [START]\n", name) defer fmt.Printf("Dump %s: [DONE]\n\n", name) info, err := getter() if err != nil { fmt.Printf("Failed to get %s: %s\n", name, err) return } data, err := json.Marshal(info) if err != nil { fmt.Printf("Failed to marshal %s: %s\n", name, err) return } fmt.Println("\t", string(data)) } hardware-0.1.8/examples/mid.go000066400000000000000000000003531407300672700162420ustar00rootroot00000000000000package main import ( "fmt" "github.com/jouyouyun/hardware" ) func main() { mid, err := hardware.GenMachineID() if err != nil { fmt.Println("Failed to generate machine id:", err) return } fmt.Println("Machine id:", mid) } hardware-0.1.8/graphic/000077500000000000000000000000001407300672700147405ustar00rootroot00000000000000hardware-0.1.8/graphic/graphic.go000066400000000000000000000014701407300672700167060ustar00rootroot00000000000000package graphic import ( "github.com/jouyouyun/hardware/utils" ) const ( graphicSysfsDir = "/sys/class/drm" ) // Graphic store graphic card info type Graphic struct { utils.CardInfo } // GraphicList store graphic card list type GraphicList []*Graphic // GetGraphicList return card list func GetGraphicList() (GraphicList, error) { list, err := utils.ScanDir(graphicSysfsDir, utils.FilterCardName) if err != nil { return nil, err } var cards GraphicList for _, name := range list { card, err := newGraphic(graphicSysfsDir, name) if err != nil { return nil, err } cards = append(cards, card) } return cards, nil } func newGraphic(dir, name string) (*Graphic, error) { card, err := utils.NewCardInfo(dir, name) if err != nil { return nil, err } return &Graphic{ CardInfo: *card, }, nil } hardware-0.1.8/hardware.go000066400000000000000000000060241407300672700154510ustar00rootroot00000000000000package hardware import ( "encoding/json" "io/ioutil" "sort" "github.com/jouyouyun/hardware/cpu" "github.com/jouyouyun/hardware/disk" hdisk "github.com/jouyouyun/hardware/disk" hdmi "github.com/jouyouyun/hardware/dmi" "github.com/jouyouyun/hardware/network" "github.com/jouyouyun/hardware/utils" ) const ( etcMachineIDFile = "/etc/machine-id" ) var ( _mid string IncludeDiskInfo bool ) // GenMachineID generate this machine's id func GenMachineID() (string, error) { if len(_mid) != 0 { return _mid, nil } var ( mid string err error dmi *hdmi.DMI disks disk.DiskList root *disk.Disk ) dmi, err = hdmi.GetDMI() if !IncludeDiskInfo && err == nil && dmi.IsValid() { mid, err = genMachineIDWithDMI(*dmi) if len(mid) != 0 { goto out } } else if dmi == nil { dmi = &hdmi.DMI{} } // if dmi product uuid null or IncludeDiskInfo is true, generate machine id with root disk serial disks, err = hdisk.GetDiskList() if err == nil { root = disks.GetRoot() if root != nil && len(root.Serial) != 0 { mid, err = genMachineIDWithDisk(*dmi, root) if len(mid) != 0 { goto out } } } mid, err = genMachineIDWithNet(*dmi) if len(mid) != 0 { goto out } mid, err = genMachineIDWithFile(etcMachineIDFile) out: _mid = mid return mid, err } func genMachineIDWithDMI(dmi hdmi.DMI) (string, error) { // bios info maybe changed after upgraded dmi.BiosDate = "" dmi.BiosVendor = "" dmi.BiosVersion = "" return doGenMachineID(&dmi) } func genMachineIDWithDisk(dmi hdmi.DMI, disk *hdisk.Disk) (string, error) { // bios info maybe changed after upgraded dmi.BiosDate = "" dmi.BiosVendor = "" dmi.BiosVersion = "" var info = struct { hdmi.DMI DiskSerial string }{ DMI: dmi, DiskSerial: disk.Serial, } return doGenMachineID(&info) } func doGenMachineID(info interface{}) (string, error) { data, err := json.Marshal(info) if err != nil { return "", err } return utils.SHA256Sum(data), nil } func genMachineIDWithNet(dmi hdmi.DMI) (string, error) { cpuInfo, err := cpu.NewCPU() if err != nil { return "", err } netInfo, err := network.GetNetworkList() if err != nil { return "", err } var ( plist []string vlist []string alist []string ) for _, info := range netInfo { plist = append(plist, info.Product) vlist = append(vlist, info.Vendor) alist = append(alist, info.Address) } sort.Strings(plist) sort.Strings(vlist) sort.Strings(alist) // bios info maybe changed after upgraded dmi.BiosDate = "" dmi.BiosVendor = "" dmi.BiosVersion = "" var info = struct { hdmi.DMI CPU string ProductList []string VendorList []string AddressList []string }{ DMI: dmi, CPU: cpuInfo.Name, ProductList: plist, VendorList: vlist, AddressList: alist, } return doGenMachineID(&info) } func genMachineIDWithFile(filename string) (string, error) { contents, err := ioutil.ReadFile(filename) if err != nil { return "", err } var info = struct { ID string }{ ID: string(contents), } return doGenMachineID(&info) } hardware-0.1.8/memory/000077500000000000000000000000001407300672700146335ustar00rootroot00000000000000hardware-0.1.8/memory/memory.go000066400000000000000000000020071407300672700164710ustar00rootroot00000000000000package memory import ( "strconv" "strings" "github.com/jouyouyun/hardware/utils" ) // Memory store memory info type Memory struct { Name string // TODO(jouyouyun): implement Manufacturer string // TODO(jouyouyun): implement Capacity int64 // kb } // MemoryList memory list type MemoryList []*Memory const ( memKeyTotal = "MemTotal" memKeyDelim = ":" memFilename = "/proc/meminfo" ) var ( _memList MemoryList ) func GetMemoryList() (MemoryList, error) { if len(_memList) == 0 { mem, err := getMemory(memFilename) if err != nil { return nil, err } _memList = MemoryList{mem} } return _memList, nil } func getMemory(filename string) (*Memory, error) { var keySet = map[string]string{memKeyTotal: ""} err := utils.ProcGetByKey(filename, memKeyDelim, keySet, false) if err != nil { return nil, err } items := strings.SplitN(keySet[memKeyTotal], " ", 2) total, err := strconv.ParseInt(items[0], 10, 64) if err != nil { return nil, err } return &Memory{Capacity: total}, nil } hardware-0.1.8/network/000077500000000000000000000000001407300672700150145ustar00rootroot00000000000000hardware-0.1.8/network/ip.c000066400000000000000000000017421407300672700155740ustar00rootroot00000000000000#include "ip.h" #include #include #include #include #include #include #include #include #include #include #define IPv4_LEN 15 char * get_iface_ip(const char *iface) { if (!iface) { return NULL; } int fd; struct ifreq ifr; fd = socket(AF_INET, SOCK_DGRAM, 0); if (fd < 0) { fprintf(stderr, "Failed to open socket: %s\n", strerror(errno)); return NULL; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_addr.sa_family = AF_INET; strncpy(ifr.ifr_name, iface, IFNAMSIZ -1); ioctl(fd, SIOCGIFADDR, &ifr); close(fd); char *ip = inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr); char *ret = calloc(IPv4_LEN+1, sizeof(char)); if (!ret) { fprintf(stderr, "Failed to alloc memory: %s\n", strerror(errno)); return NULL; } memcpy(ret, ip, IPv4_LEN); return ret; } hardware-0.1.8/network/ip.h000066400000000000000000000001321407300672700155710ustar00rootroot00000000000000#ifndef __NET_IP_H__ #define __NET_IP_H__ char *get_iface_ip(const char *iface); #endif hardware-0.1.8/network/network.go000066400000000000000000000027531407300672700170430ustar00rootroot00000000000000package network // #cgo CFLAGS: -Wall -g // #include "ip.h" // #include import "C" import ( "os" "path/filepath" "unsafe" "github.com/jouyouyun/hardware/utils" ) const ( netSysfsDir = "/sys/class/net" netVirtualDir = "/sys/devices/virtual/net" ) // Network store network info type Network struct { utils.CardInfo Address string IP string } // NetworkList network list type NetworkList []*Network // GetNetworkList return network card list func GetNetworkList() (NetworkList, error) { var netList NetworkList ifaceList, _ := utils.ScanDir(netSysfsDir, filterIface) for _, iface := range ifaceList { net, err := newNetwork(netSysfsDir, iface) if err != nil { return nil, err } netList = append(netList, net) } return netList, nil } func newNetwork(dir, iface string) (*Network, error) { card, err := utils.NewCardInfo(dir, iface) if err != nil { return nil, err } var net = Network{CardInfo: *card} net.Address, _ = utils.ReadFileContent(filepath.Join(dir, iface, "address")) net.IP = getIfaceIP(iface) return &net, nil } func getIfaceIP(iface string) string { ciface := C.CString(iface) defer C.free(unsafe.Pointer(ciface)) cret := C.get_iface_ip(ciface) defer C.free(unsafe.Pointer(cret)) ret := C.GoString(cret) return ret } func filterIface(iface string) bool { return isVirtualIface(iface, netVirtualDir) } func isVirtualIface(iface, dir string) bool { _, err := os.Stat(filepath.Join(dir, iface)) return err == nil || os.IsExist(err) } hardware-0.1.8/network/network_test.go000066400000000000000000000015751407300672700201030ustar00rootroot00000000000000package network import ( "github.com/jouyouyun/hardware/utils" "testing" ) func TestNewNetwork(t *testing.T) { info, err := newNetwork("./testdata", "jouyouyun_enp3s0") if err != nil { t.Error("failed to new network from testdata:", err) return } var v = Network{ CardInfo: utils.CardInfo{ Vendor: "10EC", Product: "8168", Slot: "pci", }, Address: "00:e0:70:c4:66:c1", IP: "0.0.0.0", } if info.Address != v.Address { t.Errorf("Address excepted %q, but %q", v.Address, info.Address) } if info.IP != v.IP { t.Errorf("IP excepted %q, but %q", v.IP, info.IP) } if info.Vendor != v.Vendor { t.Errorf("Vendor excepted %q, but %q", v.Vendor, info.Vendor) } if info.Product != v.Product { t.Errorf("Product excepted %q, but %q", v.Product, info.Product) } if info.Slot != v.Slot { t.Errorf("Slot excepted %q, but %q", v.Slot, info.Slot) } } hardware-0.1.8/network/testdata/000077500000000000000000000000001407300672700166255ustar00rootroot00000000000000hardware-0.1.8/network/testdata/jouyouyun_enp3s0/000077500000000000000000000000001407300672700221035ustar00rootroot00000000000000hardware-0.1.8/network/testdata/jouyouyun_enp3s0/address000066400000000000000000000000211407300672700234440ustar00rootroot0000000000000000:e0:70:c4:66:c1hardware-0.1.8/network/testdata/jouyouyun_enp3s0/device/000077500000000000000000000000001407300672700233425ustar00rootroot00000000000000hardware-0.1.8/network/testdata/jouyouyun_enp3s0/device/uevent000066400000000000000000000002371407300672700245750ustar00rootroot00000000000000DRIVER=r8169 PCI_CLASS=20000 PCI_ID=10EC:8168 PCI_SUBSYS_ID=1D05:6002 PCI_SLOT_NAME=0000:03:00.0 MODALIAS=pci:v000010ECd00008168sv00001D05sd00006002bc02sc00i00hardware-0.1.8/peripherals/000077500000000000000000000000001407300672700156415ustar00rootroot00000000000000hardware-0.1.8/peripherals/peripherals.go000066400000000000000000000041011407300672700205020ustar00rootroot00000000000000package peripherals import ( "fmt" "io/ioutil" "strings" ) // Peripherals store input/output device type Peripherals struct { Name string Vendor string Product string } // PeripheralsList store input/output device list type PeripheralsList []*Peripherals const ( peripheralsFilename = "/proc/bus/input/devices" ) // GetPeripheralsList return peripherals device list func GetPeripheralsList() (PeripheralsList, error) { segmentList, err := getSegmentList(peripheralsFilename) if err != nil { return nil, err } var infos PeripheralsList for _, segment := range segmentList { if len(segment) == 0 { continue } info, err := newPerpherals(segment) if err != nil { return nil, err } infos = append(infos, info) } return infos, nil } func newPerpherals(segment string) (*Peripherals, error) { set := parseSegment(segment) if len(set) == 0 { return nil, fmt.Errorf("invalid segment: %s", segment) } var info = Peripherals{ Name: set["Name"], Vendor: set["Vendor"], Product: set["Product"], } info.Name = strings.TrimLeft(info.Name, "\"") info.Name = strings.TrimRight(info.Name, "\"") return &info, nil } func parseSegment(segment string) map[string]string { var set = make(map[string]string) lines := strings.Split(segment, "\n") parseFirstLine(set, lines[0]) for i := 1; i < len(lines); i++ { if len(lines[i]) == 0 { continue } items1 := strings.SplitN(lines[i], ": ", 2) if len(items1) != 2 { continue } items2 := strings.SplitN(items1[1], "=", 2) if len(items2) != 2 { continue } set[items2[0]] = items2[1] } return set } func parseFirstLine(set map[string]string, line string) { items := strings.SplitN(line, ": ", 2) if len(items) != 2 { return } items2 := strings.Split(items[1], " ") if len(items2) != 4 { return } for i := 1; i < 3; i++ { list := strings.Split(items2[i], "=") set[list[0]] = list[1] } } func getSegmentList(filename string) ([]string, error) { content, err := ioutil.ReadFile(filename) if err != nil { return nil, err } return strings.Split(string(content), "\n\n"), nil } hardware-0.1.8/sound/000077500000000000000000000000001407300672700144535ustar00rootroot00000000000000hardware-0.1.8/sound/sound.go000066400000000000000000000013451407300672700161350ustar00rootroot00000000000000package sound import ( "github.com/jouyouyun/hardware/utils" ) const ( soundSysfsDir = "/sys/class/sound" ) // Sound store sound card info type Sound struct { utils.CardInfo } // SoundList sound card list type SoundList []*Sound // GetSoundList return sound card list func GetSoundList() (SoundList, error) { list, _ := utils.ScanDir(soundSysfsDir, utils.FilterCardName) var cards SoundList for _, name := range list { card, err := newSound(soundSysfsDir, name) if err != nil { return nil, err } cards = append(cards, card) } return cards, nil } func newSound(dir, name string) (*Sound, error) { card, err := utils.NewCardInfo(dir, name) if err != nil { return nil, err } return &Sound{CardInfo: *card}, nil } hardware-0.1.8/utils/000077500000000000000000000000001407300672700144635ustar00rootroot00000000000000hardware-0.1.8/utils/card.go000066400000000000000000000027171407300672700157320ustar00rootroot00000000000000package utils import ( "path/filepath" "strconv" ) // CardInfo store card info, such as: sound, graphic... type CardInfo struct { Name string Vendor string Product string Slot string } // NewCardInfo create card info from uevent func NewCardInfo(dir, name string) (*CardInfo, error) { uevent := filepath.Join(dir, name, "device", "uevent") uinfo, err := NewUEvent(uevent) if err != nil { return nil, err } var card = CardInfo{Name: uinfo.Name} switch uinfo.Type { case UEventTypePCI: pci := uinfo.Data.(*PCIUEvent) card.Vendor = pci.Vendor.ID card.Product = pci.Device.ID card.Slot = SlotTypePCI case UEventTypeUSB: usb := uinfo.Data.(*USBUEvent) card.Vendor = usb.Vendor card.Product = usb.Product card.Slot = SlotTypeUSB } return &card, nil } // FilterCardName filter sound,graphic card name, such as 'card0' func FilterCardName(name string) bool { return filterName(name, "card") } // FilterBluetoothName filter bluetooth device name func FilterBluetoothName(name string) bool { return filterName(name, "hci") } // FilterCameraName filter camera device name func FilterCameraName(name string) bool { return filterName(name, "video") } func filterName(name, key string) bool { klen := len(key) if len(name) <= klen { return true } tmp := string([]byte(name)[:klen]) if tmp != key { return true } // number tmp = string([]byte(name)[klen:]) _, err := strconv.Atoi(tmp) if err != nil { return true } return false } hardware-0.1.8/utils/proc_file_info.go000066400000000000000000000013471407300672700177740ustar00rootroot00000000000000package utils import ( "bufio" "fmt" "os" "strings" ) func ProcGetByKey(filename, delim string, keySet map[string]string, fall bool) error { fr, err := os.Open(filename) if err != nil { return err } defer fr.Close() l := len(keySet) count := 0 scanner := bufio.NewScanner(fr) for scanner.Scan() { if count >= l && !fall { break } text := scanner.Text() if len(text) == 0 { continue } items := strings.SplitN(text, delim, 2) if len(items) != 2 { continue } key := strings.TrimSpace(items[0]) v, ok := keySet[key] if !ok { continue } keySet[key] = strings.TrimSpace(items[1]) if len(v) == 0 { count++ } } if l != count { return fmt.Errorf("not found all keys") } return nil } hardware-0.1.8/utils/testdata/000077500000000000000000000000001407300672700162745ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir1/000077500000000000000000000000001407300672700171335ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir1/testFile1000066400000000000000000000000001407300672700207040ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir1/testFile2000066400000000000000000000000001407300672700207050ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir2/000077500000000000000000000000001407300672700171345ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir2/testFile1000066400000000000000000000000001407300672700207050ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/dir2/testFile2000066400000000000000000000000001407300672700207060ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/file.hello000066400000000000000000000000061407300672700202340ustar00rootroot00000000000000hello hardware-0.1.8/utils/testdata/proc.file000066400000000000000000000001201407300672700200710ustar00rootroot00000000000000model name: Intel I7-9750H cpu cores: 0 model name: Intel I7-9750H cpu cores: 1 hardware-0.1.8/utils/testdata/scan-dirs/000077500000000000000000000000001407300672700201575ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/scan-dirs/dir1/000077500000000000000000000000001407300672700210165ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/scan-dirs/dir1/testFile1000066400000000000000000000000001407300672700225670ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/scan-dirs/dir1/testFile2000066400000000000000000000000001407300672700225700ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/scan-dirs/dir2/000077500000000000000000000000001407300672700210175ustar00rootroot00000000000000hardware-0.1.8/utils/testdata/scan-dirs/dir2/testFile2000066400000000000000000000000001407300672700225710ustar00rootroot00000000000000hardware-0.1.8/utils/uevent.go000066400000000000000000000073621407300672700163300ustar00rootroot00000000000000package 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() } hardware-0.1.8/utils/utils.go000066400000000000000000000014711407300672700161550ustar00rootroot00000000000000package utils import ( "crypto/sha256" "fmt" "io/ioutil" "strings" ) // ReadFileContent get file content and trim the last newline func ReadFileContent(filename string) (string, error) { contents, err := ioutil.ReadFile(filename) if err != nil { return "", err } return strings.TrimRight(string(contents), "\n"), nil } // SHA256Sum sum data by sha256 func SHA256Sum(data []byte) string { if len(data) == 0 { return "" } return fmt.Sprintf("%x", sha256.Sum256(data)) } // ScanDir return needed sub directory func ScanDir(dir string, filter func(string) bool) ([]string, error) { finfos, err := ioutil.ReadDir(dir) if err != nil { return nil, err } var list []string for _, finfo := range finfos { if filter(finfo.Name()) { continue } list = append(list, finfo.Name()) } return list, nil } hardware-0.1.8/utils/utils_test.go000066400000000000000000000032551407300672700172160ustar00rootroot00000000000000package utils import ( "testing" "github.com/smartystreets/goconvey/convey" ) func TestReadFileContent(t *testing.T) { convey.Convey("Test ReadFileContent", t, func() { var value = "hello" data, err := ReadFileContent("testdata/file.hello") convey.So(data, convey.ShouldEqual, value) convey.So(err, convey.ShouldBeNil) }) } func TestSHA256Sum(t *testing.T) { convey.Convey("Test SHA256Sum", t, func() { convey.So(SHA256Sum([]byte("hello,world")), convey.ShouldEqual, "77df263f49123356d28a4a8715d25bf5b980beeeb503cab46ea61ac9f3320eda") }) } func TestScanDir(t *testing.T) { convey.Convey("Test ScanDir", t, func() { var values = []string{"dir1", "dir2"} names, err := ScanDir("testdata/scan-dirs", func(string) bool { return false }) convey.So(names, convey.ShouldResemble, values) convey.So(err, convey.ShouldBeNil) names, _ = ScanDir("testdata/scan-dirs", func(string) bool { return true }) convey.So(len(names), convey.ShouldEqual, 0) }) } func TestProcGetByKey(t *testing.T) { convey.Convey("Test ProcGetByKey", t, func() { var set = map[string]string{ "model name": "", "cpu cores": "", } err := ProcGetByKey("testdata/proc.file", ":", set, false) convey.So(err, convey.ShouldBeNil) convey.So(set["model name"], convey.ShouldEqual, "Intel I7-9750H") convey.So(set["cpu cores"], convey.ShouldEqual, "0") ProcGetByKey("testdata/proc.file", ":", set, true) convey.So(set["model name"], convey.ShouldEqual, "Intel I7-9750H") convey.So(set["cpu cores"], convey.ShouldEqual, "1") set = make(map[string]string) set["id"] = "" err = ProcGetByKey("testdata/proc.file", ":", set, true) convey.So(err, convey.ShouldNotBeNil) }) }