golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/syscall_solaris_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build solaris 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 // getOneRetry wraps EventPort.GetOne which in turn wraps a syscall that can be 22 // interrupted causing us to receive EINTR. 23 // To prevent our tests from flaking, we retry the syscall until it works 24 // rather than get unexpected results in our tests. 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 // getRetry wraps EventPort.Get which in turn wraps a syscall that can be 37 // interrupted causing us to receive EINTR. 38 // To prevent our tests from flaking, we retry the syscall until it works 39 // rather than get unexpected results in our tests. 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 // If we did get EINTR, make sure we got 0 events 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 /* SC_CLK_TCK */) 77 if err != nil { 78 t.Fatalf("Sysconf: %v", err) 79 } 80 t.Logf("Sysconf(SC_CLK_TCK) = %d", n) 81 } 82 83 // Event Ports 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 // Use a type assertion to convert the received cookie back to its original type 279 c := pevent.Cookie.(MyCookie) 280 fmt.Printf("%s", c.Name) 281 //Output: Cookie Monster 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 // Create, associate, and delete 6 files 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 // Find links and their MTU using CLI tooling 390 // $ dladm show-link -p -o link,mtu 391 // net0:1500 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 }