@@ -2,7 +2,6 @@ package main
2
2
3
3
import (
4
4
"fmt"
5
- "io"
6
5
"net"
7
6
"os"
8
7
"path/filepath"
@@ -11,14 +10,14 @@ import (
11
10
"strings"
12
11
13
12
"github.com/anatol/devmapper.go"
14
- "github.com/anatol/uevent.go "
13
+ "github.com/pilebones/go-udev/netlink "
15
14
"golang.org/x/sys/unix"
16
15
)
17
16
18
17
// validDmEvent checks whether this udev event has correct flags.
19
18
// This is similar to checks done by /usr/lib/udev/rules.d/10-dm.rules udev rules.
20
- func validDmEvent (ev * uevent. Uevent ) bool {
21
- dmCookie := ev .Vars ["DM_COOKIE" ]
19
+ func validDmEvent (ev netlink. UEvent ) bool {
20
+ dmCookie := ev .Env ["DM_COOKIE" ]
22
21
if dmCookie == "" {
23
22
info ("udev event does not contain DM_COOKIE" )
24
23
return false
@@ -63,57 +62,61 @@ func validDmEvent(ev *uevent.Uevent) bool {
63
62
return true
64
63
}
65
64
66
- var udevReader io.ReadCloser
65
+ var (
66
+ udevQuitLoop chan struct {}
67
+ udevConn * netlink.UEventConn
68
+ )
67
69
68
70
func udevListener () error {
69
- defer func () {
70
- // uevent.NewDecoder uses bufio.ReadString() that is blocking. If we try to close the underlying udev file descriptor
71
- // while bufio tries to read from it then bufio panics. See issues #22, #31 and #153
72
- // There is no clear way to prevent the panic so we just recover from it here and then safely exit the goroutine.
73
- if r := recover (); r != nil {
74
- warning ("recovered udevListener panic: %v" , r )
75
- }
76
- }()
77
-
78
- var err error
79
- udevReader , err = uevent .NewReader ()
80
- if err != nil {
81
- return err
71
+ udevConn = new (netlink.UEventConn )
72
+ if err := udevConn .Connect (netlink .KernelEvent ); err != nil {
73
+ return fmt .Errorf ("unable to connect to Netlink Kobject UEvent socket" )
82
74
}
83
- defer udevReader .Close ()
75
+ defer udevConn .Close ()
84
76
85
- dec := uevent .NewDecoder (udevReader )
77
+ queue := make (chan netlink.UEvent )
78
+ errors := make (chan error )
79
+ udevQuitLoop = udevConn .Monitor (queue , errors , nil )
86
80
81
+ exit:
87
82
for {
88
- ev , err := dec .Decode ()
89
- if err == io .EOF {
90
- // EOF is returned if uevent reader is closed concurrently
91
- return nil
92
- }
93
- if err != nil {
94
- return err
95
- }
96
- debug ("udev event %+v" , * ev )
97
-
98
- // TODO: run each udev in a separate goroutine
99
- if modalias , ok := ev .Vars ["MODALIAS" ]; ok {
100
- go func () { check (loadModalias (modalias )) }()
101
- } else if ev .Subsystem == "block" {
102
- go func () { check (handleBlockDeviceUevent (ev )) }()
103
- } else if ev .Subsystem == "net" {
104
- go func () { check (handleNetworkUevent (ev )) }()
105
- } else if ev .Subsystem == "hidraw" && ev .Action == "add" {
106
- go func () { hidrawDevices <- ev .Vars ["DEVNAME" ] }()
83
+ select {
84
+ case ev , ok := <- queue :
85
+ if ! ok {
86
+ break exit
87
+ }
88
+ handleUdevEvent (ev )
89
+ case err , ok := <- errors :
90
+ if ! ok {
91
+ break exit
92
+ }
93
+ warning ("udev: %+v" , err )
107
94
}
108
95
}
96
+
97
+ return nil
98
+ }
99
+
100
+ func handleUdevEvent (ev netlink.UEvent ) {
101
+ debug ("udev event: %+v" , ev )
102
+
103
+ if modalias , ok := ev .Env ["MODALIAS" ]; ok {
104
+ go func () { check (loadModalias (modalias )) }()
105
+ } else if ev .Env ["SUBSYSTEM" ] == "block" {
106
+ go func () { check (handleBlockDeviceUevent (ev )) }()
107
+ } else if ev .Env ["SUBSYSTEM" ] == "net" {
108
+ go func () { check (handleNetworkUevent (ev )) }()
109
+ } else if ev .Env ["SUBSYSTEM" ] == "hidraw" && ev .Action == "add" {
110
+ go func () { hidrawDevices <- ev .Env ["DEVNAME" ] }()
111
+ }
109
112
}
110
113
111
- func handleNetworkUevent (ev * uevent. Uevent ) error {
114
+ func handleNetworkUevent (ev netlink. UEvent ) error {
112
115
if ev .Action != "add" {
113
116
return nil
114
117
}
115
118
116
- ifname := ev .Vars ["INTERFACE" ]
119
+ ifname := ev .Env ["INTERFACE" ]
117
120
if ifname == "lo" {
118
121
return nil
119
122
}
@@ -140,8 +143,8 @@ func handleNetworkUevent(ev *uevent.Uevent) error {
140
143
141
144
var dmNameRe = regexp .MustCompile (`dm-\d+` )
142
145
143
- func handleBlockDeviceUevent (ev * uevent. Uevent ) error {
144
- devName := ev .Vars ["DEVNAME" ]
146
+ func handleBlockDeviceUevent (ev netlink. UEvent ) error {
147
+ devName := ev .Env ["DEVNAME" ]
145
148
146
149
if dmNameRe .MatchString (devName ) {
147
150
// mapper devices should not be added on "add" uevent
@@ -159,10 +162,10 @@ func handleBlockDeviceUevent(ev *uevent.Uevent) error {
159
162
160
163
devPath := "/dev/" + devName
161
164
162
- isPartition := ev .Vars ["DEVTYPE" ] == "partition"
165
+ isPartition := ev .Env ["DEVTYPE" ] == "partition"
163
166
if isPartition {
164
167
// if this device represents a partition inside a table (like GPT) then wait till the table is processed
165
- parts := strings .Split (ev .Devpath , "/" )
168
+ parts := strings .Split (ev .KObj , "/" )
166
169
tablePath := "/dev/" + parts [len (parts )- 2 ]
167
170
waitForDeviceToProcess (tablePath )
168
171
}
@@ -173,14 +176,14 @@ func handleBlockDeviceUevent(ev *uevent.Uevent) error {
173
176
// handleMapperDeviceUevent handles device mapper related uevent
174
177
// if udev event is valid then it return non-empty string that contains
175
178
// new mapper device name (e.g. /dev/mapper/name)
176
- func handleMapperDeviceUevent (ev * uevent. Uevent ) error {
177
- devName := ev .Vars ["DEVNAME" ]
179
+ func handleMapperDeviceUevent (ev netlink. UEvent ) error {
180
+ devName := ev .Env ["DEVNAME" ]
178
181
179
- major , err := strconv .Atoi (ev .Vars ["MAJOR" ])
182
+ major , err := strconv .Atoi (ev .Env ["MAJOR" ])
180
183
if err != nil {
181
184
return fmt .Errorf ("udev['MAJOR']: %v" , err )
182
185
}
183
- minor , err := strconv .Atoi (ev .Vars ["MINOR" ])
186
+ minor , err := strconv .Atoi (ev .Env ["MINOR" ])
184
187
if err != nil {
185
188
return fmt .Errorf ("udev['MAJOR']: %v" , err )
186
189
}
0 commit comments