-
Notifications
You must be signed in to change notification settings - Fork 28
/
main.go
145 lines (119 loc) · 3.15 KB
/
main.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
package main
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/signal"
"syscall"
"github.com/pilebones/go-udev/crawler"
"github.com/pilebones/go-udev/netlink"
"github.com/kr/pretty"
)
var (
filePath *string
monitorMode, infoMode *bool
)
func init() {
filePath = flag.String("file", "", "Optionnal input file path with matcher-rules (default: no matcher)")
monitorMode = flag.Bool("monitor", false, "Enable monitor mode")
infoMode = flag.Bool("info", false, "Enable crawler mode")
}
func main() {
flag.Parse()
matcher, err := getOptionnalMatcher()
if err != nil {
log.Fatalln(err)
}
if monitorMode == nil && infoMode == nil {
log.Fatalln("You should use only one mode:", os.Args[0], "-monitor|-info")
}
if (monitorMode != nil && *monitorMode) && (infoMode != nil && *infoMode) {
log.Fatalln("Unable to enable both mode : monitor & info")
}
if *monitorMode {
monitor(matcher)
}
if *infoMode {
info(matcher)
}
}
// info run info mode
func info(matcher netlink.Matcher) {
log.Println("Get existing devices...")
queue := make(chan crawler.Device)
errors := make(chan error)
quit := crawler.ExistingDevices(queue, errors, matcher)
// Signal handler to quit properly monitor mode
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
<-signals
log.Println("Exiting info mode...")
close(quit)
os.Exit(0)
}()
// Handling message from queue
for {
select {
case device, more := <-queue:
if !more {
log.Println("Finished processing existing devices")
return
}
log.Println("Detect device at", device.KObj, "with env", device.Env)
case err := <-errors:
log.Println("ERROR:", err)
}
}
}
// monitor run monitor mode
func monitor(matcher netlink.Matcher) {
log.Println("Monitoring UEvent kernel message to user-space...")
conn := new(netlink.UEventConn)
if err := conn.Connect(netlink.UdevEvent); err != nil {
log.Fatalln("Unable to connect to Netlink Kobject UEvent socket")
}
defer conn.Close()
queue := make(chan netlink.UEvent)
errors := make(chan error)
quit := conn.Monitor(queue, errors, matcher)
// Signal handler to quit properly monitor mode
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
<-signals
log.Println("Exiting monitor mode...")
close(quit)
os.Exit(0)
}()
// Handling message from queue
for {
select {
case uevent := <-queue:
log.Println("Handle", pretty.Sprint(uevent))
case err := <-errors:
log.Println("ERROR:", err)
}
}
}
// getOptionnalMatcher Parse and load config file which contains rules for matching
func getOptionnalMatcher() (matcher netlink.Matcher, err error) {
if filePath == nil || *filePath == "" {
return nil, nil
}
stream, err := ioutil.ReadFile(*filePath)
if err != nil {
return nil, err
}
if stream == nil {
return nil, fmt.Errorf("Empty, no rules provided in \"%s\", err: %w", *filePath, err)
}
var rules netlink.RuleDefinitions
if err := json.Unmarshal(stream, &rules); err != nil {
return nil, fmt.Errorf("Wrong rule syntax, err: %w", err)
}
return &rules, nil
}