1
2
3
4
5
6
7 package unix_test
8
9 import (
10 "fmt"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "runtime"
15 "strings"
16 "testing"
17
18 "golang.org/x/sys/unix"
19 )
20
21
22
23
24
25 func getOneRetry(t *testing.T, p *unix.EventPort, timeout *unix.Timespec) (e *unix.PortEvent, err error) {
26 t.Helper()
27 for {
28 e, err = p.GetOne(timeout)
29 if err != unix.EINTR {
30 break
31 }
32 }
33 return e, err
34 }
35
36
37
38
39
40 func getRetry(t *testing.T, p *unix.EventPort, s []unix.PortEvent, min int, timeout *unix.Timespec) (n int, err error) {
41 t.Helper()
42 for {
43 n, err = p.Get(s, min, timeout)
44 if err != unix.EINTR {
45 break
46 }
47
48 if n != 0 {
49 t.Fatalf("EventPort.Get returned events on EINTR.\ngot: %d\nexpected: 0", n)
50 }
51 }
52 return n, err
53 }
54
55 func TestStatvfs(t *testing.T) {
56 if err := unix.Statvfs("", nil); err == nil {
57 t.Fatal(`Statvfs("") expected failure`)
58 }
59
60 statvfs := unix.Statvfs_t{}
61 if err := unix.Statvfs("/", &statvfs); err != nil {
62 t.Errorf(`Statvfs("/") failed: %v`, err)
63 }
64
65 if t.Failed() {
66 mount, err := exec.Command("mount").CombinedOutput()
67 if err != nil {
68 t.Logf("mount: %v\n%s", err, mount)
69 } else {
70 t.Logf("mount: %s", mount)
71 }
72 }
73 }
74
75 func TestSysconf(t *testing.T) {
76 n, err := unix.Sysconf(3 )
77 if err != nil {
78 t.Fatalf("Sysconf: %v", err)
79 }
80 t.Logf("Sysconf(SC_CLK_TCK) = %d", n)
81 }
82
83
84
85 func TestBasicEventPort(t *testing.T) {
86 tmpfile, err := os.Create(filepath.Join(t.TempDir(), "eventport"))
87 if err != nil {
88 t.Fatal(err)
89 }
90 defer tmpfile.Close()
91 path := tmpfile.Name()
92
93 stat, err := os.Stat(path)
94 if err != nil {
95 t.Fatalf("Failed to stat %s: %v", path, err)
96 }
97 port, err := unix.NewEventPort()
98 if err != nil {
99 t.Fatalf("NewEventPort failed: %v", err)
100 }
101 defer port.Close()
102 cookie := stat.Mode()
103 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, cookie)
104 if err != nil {
105 t.Errorf("AssociatePath failed: %v", err)
106 }
107 if !port.PathIsWatched(path) {
108 t.Errorf("PathIsWatched unexpectedly returned false")
109 }
110 err = port.DissociatePath(path)
111 if err != nil {
112 t.Errorf("DissociatePath failed: %v", err)
113 }
114 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, cookie)
115 if err != nil {
116 t.Errorf("AssociatePath failed: %v", err)
117 }
118 bs := []byte{42}
119 tmpfile.Write(bs)
120 timeout := new(unix.Timespec)
121 timeout.Nsec = 100
122 pevent, err := getOneRetry(t, port, timeout)
123 if err == unix.ETIME {
124 t.Errorf("GetOne timed out: %v", err)
125 }
126 if err != nil {
127 t.Fatalf("GetOne failed: %v", err)
128 }
129 if pevent.Path != path {
130 t.Errorf("Path mismatch: %v != %v", pevent.Path, path)
131 }
132 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, cookie)
133 if err != nil {
134 t.Errorf("AssociatePath failed: %v", err)
135 }
136 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, cookie)
137 if err == nil {
138 t.Errorf("Unexpected success associating already associated path")
139 }
140 }
141
142 func TestEventPortFds(t *testing.T) {
143 _, path, _, _ := runtime.Caller(0)
144 stat, err := os.Stat(path)
145 cookie := stat.Mode()
146 port, err := unix.NewEventPort()
147 if err != nil {
148 t.Errorf("NewEventPort failed: %v", err)
149 }
150 defer port.Close()
151 r, w, err := os.Pipe()
152 if err != nil {
153 t.Errorf("unable to create a pipe: %v", err)
154 }
155 defer w.Close()
156 defer r.Close()
157 fd := r.Fd()
158
159 port.AssociateFd(fd, unix.POLLIN, cookie)
160 if !port.FdIsWatched(fd) {
161 t.Errorf("FdIsWatched unexpectedly returned false")
162 }
163 err = port.DissociateFd(fd)
164 err = port.AssociateFd(fd, unix.POLLIN, cookie)
165 bs := []byte{42}
166 w.Write(bs)
167 n, err := port.Pending()
168 if n != 1 {
169 t.Errorf("Pending() failed: %v, %v", n, err)
170 }
171 timeout := new(unix.Timespec)
172 timeout.Nsec = 100
173 pevent, err := getOneRetry(t, port, timeout)
174 if err == unix.ETIME {
175 t.Errorf("GetOne timed out: %v", err)
176 }
177 if err != nil {
178 t.Fatalf("GetOne failed: %v", err)
179 }
180 if pevent.Fd != fd {
181 t.Errorf("Fd mismatch: %v != %v", pevent.Fd, fd)
182 }
183 var c = pevent.Cookie
184 if c == nil {
185 t.Errorf("Cookie missing: %v != %v", cookie, c)
186 return
187 }
188 if c != cookie {
189 t.Errorf("Cookie mismatch: %v != %v", cookie, c)
190 }
191 port.AssociateFd(fd, unix.POLLIN, cookie)
192 err = port.AssociateFd(fd, unix.POLLIN, cookie)
193 if err == nil {
194 t.Errorf("unexpected success associating already associated fd")
195 }
196 }
197
198 func TestEventPortErrors(t *testing.T) {
199 tmpfile, err := os.CreateTemp("", "eventport")
200 if err != nil {
201 t.Errorf("unable to create a tempfile: %v", err)
202 }
203 path := tmpfile.Name()
204 stat, _ := os.Stat(path)
205 os.Remove(path)
206 port, _ := unix.NewEventPort()
207 defer port.Close()
208 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, nil)
209 if err == nil {
210 t.Errorf("unexpected success associating nonexistant file")
211 }
212 err = port.DissociatePath(path)
213 if err == nil {
214 t.Errorf("unexpected success dissociating unassociated path")
215 }
216 timeout := new(unix.Timespec)
217 timeout.Nsec = 1
218 _, err = getOneRetry(t, port, timeout)
219 if err != unix.ETIME {
220 t.Errorf("port.GetOne(%v) returned error %v, want %v", timeout, err, unix.ETIME)
221 }
222 err = port.DissociateFd(uintptr(0))
223 if err == nil {
224 t.Errorf("unexpected success dissociating unassociated fd")
225 }
226 events := make([]unix.PortEvent, 4)
227 _, err = getRetry(t, port, events, 5, nil)
228 if err == nil {
229 t.Errorf("unexpected success calling Get with min greater than len of slice")
230 }
231 _, err = getRetry(t, port, nil, 1, nil)
232 if err == nil {
233 t.Errorf("unexpected success calling Get with nil slice")
234 }
235 _, err = getRetry(t, port, nil, 0, nil)
236 if err == nil {
237 t.Errorf("unexpected success calling Get with nil slice")
238 }
239 }
240
241 func ExamplePortEvent() {
242 type MyCookie struct {
243 Name string
244 }
245 cookie := MyCookie{"Cookie Monster"}
246 port, err := unix.NewEventPort()
247 if err != nil {
248 fmt.Printf("NewEventPort failed: %v\n", err)
249 return
250 }
251 defer port.Close()
252 r, w, err := os.Pipe()
253 if err != nil {
254 fmt.Printf("os.Pipe() failed: %v\n", err)
255 return
256 }
257 defer w.Close()
258 defer r.Close()
259 fd := r.Fd()
260
261 port.AssociateFd(fd, unix.POLLIN, cookie)
262
263 bs := []byte{42}
264 w.Write(bs)
265 timeout := new(unix.Timespec)
266 timeout.Sec = 1
267 var pevent *unix.PortEvent
268 for {
269 pevent, err = port.GetOne(timeout)
270 if err != unix.EINTR {
271 break
272 }
273 }
274 if err != nil {
275 fmt.Printf("didn't get the expected event: %v\n", err)
276 }
277
278
279 c := pevent.Cookie.(MyCookie)
280 fmt.Printf("%s", c.Name)
281
282 }
283
284 func TestPortEventSlices(t *testing.T) {
285 port, err := unix.NewEventPort()
286 if err != nil {
287 t.Fatalf("NewEventPort failed: %v", err)
288 }
289
290 for i := 0; i < 6; i++ {
291 tmpfile, err := os.CreateTemp("", "eventport")
292 if err != nil {
293 t.Fatalf("unable to create tempfile: %v", err)
294 }
295 path := tmpfile.Name()
296 stat, err := os.Stat(path)
297 if err != nil {
298 t.Fatalf("unable to stat tempfile: %v", err)
299 }
300 err = port.AssociatePath(path, stat, unix.FILE_MODIFIED, nil)
301 if err != nil {
302 t.Fatalf("unable to AssociatePath tempfile: %v", err)
303 }
304 err = os.Remove(path)
305 if err != nil {
306 t.Fatalf("unable to Remove tempfile: %v", err)
307 }
308 }
309 n, err := port.Pending()
310 if err != nil {
311 t.Errorf("Pending failed: %v", err)
312 }
313 if n != 6 {
314 t.Errorf("expected 6 pending events, got %d", n)
315 }
316 timeout := new(unix.Timespec)
317 timeout.Nsec = 1
318 events := make([]unix.PortEvent, 4)
319 n, err = getRetry(t, port, events, 3, timeout)
320 if err != nil {
321 t.Errorf("Get failed: %v", err)
322 }
323 if n != 4 {
324 t.Errorf("expected 4 events, got %d", n)
325 }
326 e := events[:n]
327 for _, p := range e {
328 if p.Events != unix.FILE_DELETE {
329 t.Errorf("unexpected event. got %v, expected %v", p.Events, unix.FILE_DELETE)
330 }
331 }
332 n, err = getRetry(t, port, events, 3, timeout)
333 if err != unix.ETIME {
334 t.Errorf("unexpected error. got %v, expected %v", err, unix.ETIME)
335 }
336 if n != 2 {
337 t.Errorf("expected 2 events, got %d", n)
338 }
339 e = events[:n]
340 for _, p := range e {
341 if p.Events != unix.FILE_DELETE {
342 t.Errorf("unexpected event. got %v, expected %v", p.Events, unix.FILE_DELETE)
343 }
344 }
345
346 r, w, err := os.Pipe()
347 if err != nil {
348 t.Fatalf("unable to create a pipe: %v", err)
349 }
350 port.AssociateFd(r.Fd(), unix.POLLIN, nil)
351 port.AssociateFd(w.Fd(), unix.POLLOUT, nil)
352 bs := []byte{41}
353 w.Write(bs)
354
355 n, err = getRetry(t, port, events, 1, timeout)
356 if err != nil {
357 t.Errorf("Get failed: %v", err)
358 }
359 if n != 2 {
360 t.Errorf("expected 2 events, got %d", n)
361 }
362 err = w.Close()
363 if err != nil {
364 t.Errorf("w.Close() failed: %v", err)
365 }
366 err = r.Close()
367 if err != nil {
368 t.Errorf("r.Close() failed: %v", err)
369 }
370 err = port.Close()
371 if err != nil {
372 t.Errorf("port.Close() failed: %v", err)
373 }
374 }
375
376 func TestLifreqSetName(t *testing.T) {
377 var l unix.Lifreq
378 err := l.SetName("12345678901234356789012345678901234567890")
379 if err == nil {
380 t.Fatal(`Lifreq.SetName should reject names that are too long`)
381 }
382 err = l.SetName("tun0")
383 if err != nil {
384 t.Errorf(`Lifreq.SetName("tun0") failed: %v`, err)
385 }
386 }
387
388 func TestLifreqGetMTU(t *testing.T) {
389
390
391
392 out, err := exec.Command("dladm", "show-link", "-p", "-o", "link,mtu").Output()
393 if err != nil {
394 t.Fatalf("unable to use dladm to find data links: %v", err)
395 }
396 lines := strings.Split(string(out), "\n")
397 tc := make(map[string]string)
398 for _, line := range lines {
399 v := strings.Split(line, ":")
400 if len(v) == 2 {
401 tc[v[0]] = v[1]
402 }
403 }
404 ip_fd, err := unix.Socket(unix.AF_INET, unix.SOCK_DGRAM, 0)
405 if err != nil {
406 t.Fatalf("could not open udp socket: %v", err)
407 }
408 var l unix.Lifreq
409 for link, mtu := range tc {
410 err = l.SetName(link)
411 if err != nil {
412 t.Fatalf("Lifreq.SetName(%q) failed: %v", link, err)
413 }
414 if err = unix.IoctlLifreq(ip_fd, unix.SIOCGLIFMTU, &l); err != nil {
415 t.Fatalf("unable to SIOCGLIFMTU: %v", err)
416 }
417 m := l.GetLifruUint()
418 if fmt.Sprintf("%d", m) != mtu {
419 t.Errorf("unable to read MTU correctly: expected %s, got %d", mtu, m)
420 }
421 }
422 }
423
View as plain text