-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusb.go
192 lines (170 loc) · 4.82 KB
/
usb.go
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
183
184
185
186
187
188
189
190
191
192
package main
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
// USBDevice represents a connected USB device
type USBDevice struct {
ID string
Name string
BusCount map[string]uint8
}
// USBTracker represents the USB tracking service
type USBTracker struct {
Config *Config
cachedDevices map[string]USBDevice
}
// NewUSBTracker creates a new USBTracker instance
func NewUSBTracker(config *Config) *USBTracker {
return &USBTracker{
Config: config,
}
}
// InitUSBDevices initializes the USB devices list
func (u *USBTracker) InitUSBDevices(verbose bool) {
u.cachedDevices = u.getConnectedUSBDevices()
if verbose {
fmt.Println("Connected at start:\nID\t\t\tCount\tName")
for id, device := range u.cachedDevices {
sum := uint8(0)
for _, count := range device.BusCount {
sum += count
}
str := id + "\t" + strconv.Itoa(int(sum)) + "\t\t" + device.Name
fmt.Println(str)
}
}
}
// TrackUSBDevices tracks connected USB devices. Meant to be executed periodically
func (u *USBTracker) TrackUSBDevices(noExec, debug bool) {
// Get list of currently connected USB devices
currentDevices := u.getConnectedUSBDevices()
// Check for new devices
for id, device := range currentDevices {
if !u.deviceIDExists(id) {
// New device ID found
if !u.deviceIDIgnored(id) {
// ID not ignored -> execute commands
u.Config.log("New ID: " + id + " Name: " + device.Name)
u.Config.exec(CalleeUSB, noExec)
} else if debug {
u.Config.log("New device from ignored IDs: " + id + " Name: " + device.Name)
}
// Add device to cache as it is now registered
u.cachedDevices[id] = device
} else {
// Device ID is known
if !device.isBusCountEqual(u.cachedDevices[id]) {
// Number of devices with same ID is not same as before
if !u.deviceIDIgnored(id) {
// ID not ignored -> execute commands
cacheDevice := u.cachedDevices[id]
u.Config.log("Device count differs for ID: " + id + " Name: " + device.Name)
u.Config.log("Old count: " + strconv.Itoa(int(cacheDevice.getBusSum())) + " | New Count: " + strconv.Itoa(int(device.getBusSum())))
u.Config.exec(CalleeUSB, noExec)
} else if debug {
u.Config.log("Device count differs for ignored ID: " + id + " Name: " + device.Name)
}
u.cachedDevices[id] = device
}
}
}
// Check for missing devices
for id, device := range u.cachedDevices {
if deviceIDMissing(currentDevices, id) {
if !u.deviceIDIgnored(id) {
u.Config.log("Old missing ID: " + id + " Name: " + device.Name)
u.Config.exec(CalleeUSB, noExec)
} else {
if debug {
u.Config.log("Ignored missing device ID: " + id + " Name: " + device.Name)
}
}
// Delete as state is updated
delete(u.cachedDevices, id)
}
}
}
// getConnectedUSBDevices retrieves currently connected USB devices
func (u *USBTracker) getConnectedUSBDevices() map[string]USBDevice {
output, err := exec.Command("lsusb").Output()
if err != nil {
u.Config.logErr(err)
return nil
}
devices := make(map[string]USBDevice)
lines := strings.Split(string(output), "\n")
for _, line := range lines {
parts := strings.Fields(line)
if len(parts) >= 6 {
id := parts[5]
bus := parts[1]
name := combineFields(parts, 6)
if u, ok := devices[id]; ok {
if _, ok := u.BusCount[bus]; ok {
devices[id].BusCount[bus] += 1
} else {
devices[id].BusCount[bus] = 1
}
} else {
m := make(map[string]uint8)
m[bus] = 1
devices[id] = USBDevice{ID: id, Name: name, BusCount: m}
}
}
}
return devices
}
// deviceIDIgnored checks if a device ID is ignored
func (u *USBTracker) deviceIDIgnored(id string) bool {
return has(u.Config.IgnoredIDs, id)
}
// deviceIDExists checks if a device ID already exists in the cache
func (u *USBTracker) deviceIDExists(id string) bool {
_, exists := u.cachedDevices[id]
return exists
}
func (u *USBDevice) isBusCountEqual(u2 USBDevice) bool {
if len(u.BusCount) != len(u2.BusCount) {
return false
}
for bus, count := range u.BusCount {
if u2.BusCount[bus] != count {
return false
}
}
return true
}
func (u *USBDevice) getBusSum() uint8 {
busSum := uint8(0)
for _, c := range u.BusCount {
busSum += c
}
return busSum
}
func deviceIDMissing(current map[string]USBDevice, id string) bool {
_, exists := current[id]
return !exists
}
func combineFields(array []string, startIndex int) string {
// Initialize an empty string to store the combined fields
var combined string
// Iterate over the array starting from the second element
for i := startIndex; i < len(array); i++ {
// Append each field to the combined string with a whitespace delimiter
combined += array[i] + " "
}
// Trim any trailing whitespace
combined = strings.TrimSpace(combined)
return combined
}
func has(array []string, id string) bool {
for _, s := range array {
if s == id {
return true
}
}
return false
}