golang.org/x/sys@v0.9.0/unix/syscall_unix_test.go (about) 1 // Copyright 2013 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 aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 7 8 package unix_test 9 10 import ( 11 "bytes" 12 "flag" 13 "fmt" 14 "io/ioutil" 15 "net" 16 "os" 17 "os/exec" 18 "path/filepath" 19 "reflect" 20 "runtime" 21 "strconv" 22 "sync" 23 "syscall" 24 "testing" 25 "time" 26 27 "golang.org/x/sys/unix" 28 ) 29 30 // Tests that below functions, structures and constants are consistent 31 // on all Unix-like systems. 32 func _() { 33 // program scheduling priority functions and constants 34 var ( 35 _ func(int, int, int) error = unix.Setpriority 36 _ func(int, int) (int, error) = unix.Getpriority 37 ) 38 const ( 39 _ int = unix.PRIO_USER 40 _ int = unix.PRIO_PROCESS 41 _ int = unix.PRIO_PGRP 42 ) 43 44 // termios constants 45 const ( 46 _ int = unix.TCIFLUSH 47 _ int = unix.TCIOFLUSH 48 _ int = unix.TCOFLUSH 49 ) 50 51 // fcntl file locking structure and constants 52 var ( 53 _ = unix.Flock_t{ 54 Type: int16(0), 55 Whence: int16(0), 56 Start: int64(0), 57 Len: int64(0), 58 Pid: int32(0), 59 } 60 ) 61 const ( 62 _ = unix.F_GETLK 63 _ = unix.F_SETLK 64 _ = unix.F_SETLKW 65 ) 66 } 67 68 func TestErrnoSignalName(t *testing.T) { 69 testErrors := []struct { 70 num syscall.Errno 71 name string 72 }{ 73 {syscall.EPERM, "EPERM"}, 74 {syscall.EINVAL, "EINVAL"}, 75 {syscall.ENOENT, "ENOENT"}, 76 } 77 78 for _, te := range testErrors { 79 t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) { 80 e := unix.ErrnoName(te.num) 81 if e != te.name { 82 t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name) 83 } 84 }) 85 } 86 87 testSignals := []struct { 88 num syscall.Signal 89 name string 90 }{ 91 {syscall.SIGHUP, "SIGHUP"}, 92 {syscall.SIGPIPE, "SIGPIPE"}, 93 {syscall.SIGSEGV, "SIGSEGV"}, 94 } 95 96 for _, ts := range testSignals { 97 t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) { 98 s := unix.SignalName(ts.num) 99 if s != ts.name { 100 t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name) 101 } 102 }) 103 } 104 } 105 106 func TestSignalNum(t *testing.T) { 107 testSignals := []struct { 108 name string 109 want syscall.Signal 110 }{ 111 {"SIGHUP", syscall.SIGHUP}, 112 {"SIGPIPE", syscall.SIGPIPE}, 113 {"SIGSEGV", syscall.SIGSEGV}, 114 {"NONEXISTS", 0}, 115 } 116 for _, ts := range testSignals { 117 t.Run(fmt.Sprintf("%s/%d", ts.name, ts.want), func(t *testing.T) { 118 got := unix.SignalNum(ts.name) 119 if got != ts.want { 120 t.Errorf("SignalNum(%s) returned %d, want %d", ts.name, got, ts.want) 121 } 122 }) 123 124 } 125 } 126 127 func TestFcntlInt(t *testing.T) { 128 t.Parallel() 129 file, err := ioutil.TempFile("", "TestFcntlInt") 130 if err != nil { 131 t.Fatal(err) 132 } 133 defer os.Remove(file.Name()) 134 defer file.Close() 135 f := file.Fd() 136 flags, err := unix.FcntlInt(f, unix.F_GETFD, 0) 137 if err != nil { 138 t.Fatal(err) 139 } 140 if flags&unix.FD_CLOEXEC == 0 { 141 t.Errorf("flags %#x do not include FD_CLOEXEC", flags) 142 } 143 } 144 145 // TestFcntlFlock tests whether the file locking structure matches 146 // the calling convention of each kernel. 147 func TestFcntlFlock(t *testing.T) { 148 name := filepath.Join(os.TempDir(), "TestFcntlFlock") 149 fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) 150 if err != nil { 151 t.Fatalf("Open failed: %v", err) 152 } 153 defer unix.Unlink(name) 154 defer unix.Close(fd) 155 flock := unix.Flock_t{ 156 Type: unix.F_RDLCK, 157 Start: 0, Len: 0, Whence: 1, 158 } 159 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { 160 t.Fatalf("FcntlFlock failed: %v", err) 161 } 162 } 163 164 // TestPassFD tests passing a file descriptor over a Unix socket. 165 // 166 // This test involved both a parent and child process. The parent 167 // process is invoked as a normal test, with "go test", which then 168 // runs the child process by running the current test binary with args 169 // "-test.run=^TestPassFD$" and an environment variable used to signal 170 // that the test should become the child process instead. 171 func TestPassFD(t *testing.T) { 172 if runtime.GOOS == "ios" { 173 t.Skip("cannot exec subprocess on iOS, skipping test") 174 } 175 176 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 177 passFDChild() 178 return 179 } 180 181 if runtime.GOOS == "aix" { 182 // Unix network isn't properly working on AIX 183 // 7.2 with Technical Level < 2 184 out, err := exec.Command("oslevel", "-s").Output() 185 if err != nil { 186 t.Skipf("skipping on AIX because oslevel -s failed: %v", err) 187 } 188 189 if len(out) < len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM 190 t.Skip("skipping on AIX because oslevel -s hasn't the right length") 191 } 192 aixVer := string(out[:4]) 193 tl, err := strconv.Atoi(string(out[5:7])) 194 if err != nil { 195 t.Skipf("skipping on AIX because oslevel -s output cannot be parsed: %v", err) 196 } 197 if aixVer < "7200" || (aixVer == "7200" && tl < 2) { 198 t.Skip("skipped on AIX versions previous to 7.2 TL 2") 199 } 200 } 201 202 tempDir, err := ioutil.TempDir("", "TestPassFD") 203 if err != nil { 204 t.Fatal(err) 205 } 206 defer os.RemoveAll(tempDir) 207 208 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 209 if err != nil { 210 t.Fatalf("Socketpair: %v", err) 211 } 212 writeFile := os.NewFile(uintptr(fds[0]), "child-writes") 213 readFile := os.NewFile(uintptr(fds[1]), "parent-reads") 214 defer writeFile.Close() 215 defer readFile.Close() 216 217 cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) 218 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 219 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { 220 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) 221 } 222 cmd.ExtraFiles = []*os.File{writeFile} 223 224 out, err := cmd.CombinedOutput() 225 if len(out) > 0 || err != nil { 226 t.Fatalf("child process: %q, %v", out, err) 227 } 228 229 c, err := net.FileConn(readFile) 230 if err != nil { 231 t.Fatalf("FileConn: %v", err) 232 } 233 defer c.Close() 234 235 uc, ok := c.(*net.UnixConn) 236 if !ok { 237 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) 238 } 239 240 buf := make([]byte, 32) // expect 1 byte 241 oob := make([]byte, 32) // expect 24 bytes 242 closeUnix := time.AfterFunc(5*time.Second, func() { 243 t.Logf("timeout reading from unix socket") 244 uc.Close() 245 }) 246 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) 247 if err != nil { 248 t.Fatalf("ReadMsgUnix: %v", err) 249 } 250 closeUnix.Stop() 251 252 scms, err := unix.ParseSocketControlMessage(oob[:oobn]) 253 if err != nil { 254 t.Fatalf("ParseSocketControlMessage: %v", err) 255 } 256 if len(scms) != 1 { 257 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) 258 } 259 scm := scms[0] 260 gotFds, err := unix.ParseUnixRights(&scm) 261 if err != nil { 262 t.Fatalf("unix.ParseUnixRights: %v", err) 263 } 264 if len(gotFds) != 1 { 265 t.Fatalf("wanted 1 fd; got %#v", gotFds) 266 } 267 268 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") 269 defer f.Close() 270 271 got, err := ioutil.ReadAll(f) 272 want := "Hello from child process!\n" 273 if string(got) != want { 274 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) 275 } 276 } 277 278 // passFDChild is the child process used by TestPassFD. 279 func passFDChild() { 280 defer os.Exit(0) 281 282 // Look for our fd. It should be fd 3, but we work around an fd leak 283 // bug here (http://golang.org/issue/2603) to let it be elsewhere. 284 var uc *net.UnixConn 285 for fd := uintptr(3); fd <= 10; fd++ { 286 f := os.NewFile(fd, "unix-conn") 287 var ok bool 288 netc, _ := net.FileConn(f) 289 uc, ok = netc.(*net.UnixConn) 290 if ok { 291 break 292 } 293 } 294 if uc == nil { 295 fmt.Println("failed to find unix fd") 296 return 297 } 298 299 // Make a file f to send to our parent process on uc. 300 // We make it in tempDir, which our parent will clean up. 301 flag.Parse() 302 tempDir := flag.Arg(0) 303 f, err := ioutil.TempFile(tempDir, "") 304 if err != nil { 305 fmt.Printf("TempFile: %v", err) 306 return 307 } 308 309 f.Write([]byte("Hello from child process!\n")) 310 f.Seek(0, 0) 311 312 rights := unix.UnixRights(int(f.Fd())) 313 dummyByte := []byte("x") 314 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) 315 if err != nil { 316 fmt.Printf("WriteMsgUnix: %v", err) 317 return 318 } 319 if n != 1 || oobn != len(rights) { 320 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) 321 return 322 } 323 } 324 325 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, ParseOneSocketControlMessage, 326 // and ParseUnixRights are able to successfully round-trip lists of file descriptors. 327 func TestUnixRightsRoundtrip(t *testing.T) { 328 testCases := [...][][]int{ 329 {{42}}, 330 {{1, 2}}, 331 {{3, 4, 5}}, 332 {{}}, 333 {{1, 2}, {3, 4, 5}, {}, {7}}, 334 } 335 for _, testCase := range testCases { 336 b := []byte{} 337 var n int 338 for _, fds := range testCase { 339 // Last assignment to n wins 340 n = len(b) + unix.CmsgLen(4*len(fds)) 341 b = append(b, unix.UnixRights(fds...)...) 342 } 343 // Truncate b 344 b = b[:n] 345 346 scms, err := unix.ParseSocketControlMessage(b) 347 if err != nil { 348 t.Fatalf("ParseSocketControlMessage: %v", err) 349 } 350 if len(scms) != len(testCase) { 351 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) 352 } 353 354 var c int 355 for len(b) > 0 { 356 hdr, data, remainder, err := unix.ParseOneSocketControlMessage(b) 357 if err != nil { 358 t.Fatalf("ParseOneSocketControlMessage: %v", err) 359 } 360 if scms[c].Header != hdr || !bytes.Equal(scms[c].Data, data) { 361 t.Fatal("expected SocketControlMessage header and data to match") 362 } 363 b = remainder 364 c++ 365 } 366 if c != len(scms) { 367 t.Fatalf("expected %d SocketControlMessages; got %d", len(scms), c) 368 } 369 370 for i, scm := range scms { 371 gotFds, err := unix.ParseUnixRights(&scm) 372 if err != nil { 373 t.Fatalf("ParseUnixRights: %v", err) 374 } 375 wantFds := testCase[i] 376 if len(gotFds) != len(wantFds) { 377 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) 378 } 379 for j, fd := range gotFds { 380 if fd != wantFds[j] { 381 t.Fatalf("expected fd %v, got %v", wantFds[j], fd) 382 } 383 } 384 } 385 } 386 } 387 388 func TestRlimit(t *testing.T) { 389 var rlimit, zero unix.Rlimit 390 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) 391 if err != nil { 392 t.Fatalf("Getrlimit: save failed: %v", err) 393 } 394 if zero == rlimit { 395 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) 396 } 397 set := rlimit 398 set.Cur = set.Max - 1 399 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 { 400 // rlim_min for RLIMIT_NOFILE should be equal to 401 // or lower than kern.maxfilesperproc, which on 402 // some machines are 4096. See #40564. 403 set.Cur = 4096 404 } 405 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) 406 if err != nil { 407 t.Fatalf("Setrlimit: set failed: %#v %v", set, err) 408 } 409 var get unix.Rlimit 410 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) 411 if err != nil { 412 t.Fatalf("Getrlimit: get failed: %v", err) 413 } 414 set = rlimit 415 set.Cur = set.Max - 1 416 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 { 417 set.Cur = 4096 418 } 419 if set != get { 420 // Seems like Darwin requires some privilege to 421 // increase the soft limit of rlimit sandbox, though 422 // Setrlimit never reports an error. 423 switch runtime.GOOS { 424 case "darwin", "ios": 425 default: 426 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) 427 } 428 } 429 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) 430 if err != nil { 431 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) 432 } 433 434 // make sure RLIM_INFINITY can be assigned to Rlimit members 435 _ = unix.Rlimit{ 436 Cur: unix.RLIM_INFINITY, 437 Max: unix.RLIM_INFINITY, 438 } 439 } 440 441 func TestSeekFailure(t *testing.T) { 442 _, err := unix.Seek(-1, 0, 0) 443 if err == nil { 444 t.Fatalf("Seek(-1, 0, 0) did not fail") 445 } 446 str := err.Error() // used to crash on Linux 447 t.Logf("Seek: %v", str) 448 if str == "" { 449 t.Fatalf("Seek(-1, 0, 0) return error with empty message") 450 } 451 } 452 453 func TestSetsockoptString(t *testing.T) { 454 // should not panic on empty string, see issue #31277 455 err := unix.SetsockoptString(-1, 0, 0, "") 456 if err == nil { 457 t.Fatalf("SetsockoptString: did not fail") 458 } 459 } 460 461 func TestDup(t *testing.T) { 462 file, err := ioutil.TempFile("", "TestDup") 463 if err != nil { 464 t.Fatalf("Tempfile failed: %v", err) 465 } 466 defer os.Remove(file.Name()) 467 defer file.Close() 468 f := int(file.Fd()) 469 470 newFd, err := unix.Dup(f) 471 if err != nil { 472 t.Fatalf("Dup: %v", err) 473 } 474 475 // Create and reserve a file descriptor. 476 // Dup2 automatically closes it before reusing it. 477 nullFile, err := os.Open("/dev/null") 478 if err != nil { 479 t.Fatal(err) 480 } 481 dupFd := int(file.Fd()) 482 err = unix.Dup2(newFd, dupFd) 483 if err != nil { 484 t.Fatalf("Dup2: %v", err) 485 } 486 // Keep the dummy file open long enough to not be closed in 487 // its finalizer. 488 runtime.KeepAlive(nullFile) 489 490 b1 := []byte("Test123") 491 b2 := make([]byte, 7) 492 _, err = unix.Write(dupFd, b1) 493 if err != nil { 494 t.Fatalf("Write to dup2 fd failed: %v", err) 495 } 496 _, err = unix.Seek(f, 0, 0) 497 if err != nil { 498 t.Fatalf("Seek failed: %v", err) 499 } 500 _, err = unix.Read(f, b2) 501 if err != nil { 502 t.Fatalf("Read back failed: %v", err) 503 } 504 if string(b1) != string(b2) { 505 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) 506 } 507 } 508 509 func TestPoll(t *testing.T) { 510 if runtime.GOOS == "android" || runtime.GOOS == "ios" { 511 t.Skip("mkfifo syscall is not available on android and iOS, skipping test") 512 } 513 514 defer chtmpdir(t)() 515 f, cleanup := mktmpfifo(t) 516 defer cleanup() 517 518 const timeout = 100 519 520 ok := make(chan bool, 1) 521 go func() { 522 select { 523 case <-time.After(10 * timeout * time.Millisecond): 524 t.Errorf("Poll: failed to timeout after %d milliseconds", 10*timeout) 525 case <-ok: 526 } 527 }() 528 529 for { 530 fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}} 531 n, err := unix.Poll(fds, timeout) 532 ok <- true 533 if err == unix.EINTR { 534 t.Logf("Poll interrupted") 535 continue 536 } else if err != nil { 537 t.Errorf("Poll: unexpected error: %v", err) 538 return 539 } 540 if n != 0 { 541 t.Errorf("Poll: wrong number of events: got %v, expected %v", n, 0) 542 543 // Identify which event(s) caused Poll to return. 544 // We can't trivially use a table here because Revents 545 // isn't the same type on all systems. 546 if fds[0].Revents&unix.POLLIN != 0 { 547 t.Log("found POLLIN event") 548 } 549 if fds[0].Revents&unix.POLLPRI != 0 { 550 t.Log("found POLLPRI event") 551 } 552 if fds[0].Revents&unix.POLLOUT != 0 { 553 t.Log("found POLLOUT event") 554 } 555 if fds[0].Revents&unix.POLLERR != 0 { 556 t.Log("found POLLERR event") 557 } 558 if fds[0].Revents&unix.POLLHUP != 0 { 559 t.Log("found POLLHUP event") 560 } 561 if fds[0].Revents&unix.POLLNVAL != 0 { 562 t.Log("found POLLNVAL event") 563 } 564 } 565 break 566 } 567 } 568 569 func TestSelect(t *testing.T) { 570 for { 571 n, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) 572 if err == unix.EINTR { 573 t.Logf("Select interrupted") 574 continue 575 } else if err != nil { 576 t.Fatalf("Select: %v", err) 577 } 578 if n != 0 { 579 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 580 } 581 break 582 } 583 584 dur := 250 * time.Millisecond 585 var took time.Duration 586 for { 587 // On some platforms (e.g. Linux), the passed-in timeval is 588 // updated by select(2). Make sure to reset to the full duration 589 // in case of an EINTR. 590 tv := unix.NsecToTimeval(int64(dur)) 591 start := time.Now() 592 n, err := unix.Select(0, nil, nil, nil, &tv) 593 took = time.Since(start) 594 if err == unix.EINTR { 595 t.Logf("Select interrupted after %v", took) 596 continue 597 } else if err != nil { 598 t.Fatalf("Select: %v", err) 599 } 600 if n != 0 { 601 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 602 } 603 break 604 } 605 606 // On some platforms (e.g. NetBSD) the actual timeout might be arbitrarily 607 // less than requested. However, Linux in particular promises to only return 608 // early if a file descriptor becomes ready (not applicable here), or the call 609 // is interrupted by a signal handler (explicitly retried in the loop above), 610 // or the timeout expires. 611 if took < dur { 612 if runtime.GOOS == "linux" { 613 t.Errorf("Select: slept for %v, expected %v", took, dur) 614 } else { 615 t.Logf("Select: slept for %v, requested %v", took, dur) 616 } 617 } 618 619 rr, ww, err := os.Pipe() 620 if err != nil { 621 t.Fatal(err) 622 } 623 defer rr.Close() 624 defer ww.Close() 625 626 if _, err := ww.Write([]byte("HELLO GOPHER")); err != nil { 627 t.Fatal(err) 628 } 629 630 rFdSet := &unix.FdSet{} 631 fd := int(rr.Fd()) 632 rFdSet.Set(fd) 633 634 for { 635 n, err := unix.Select(fd+1, rFdSet, nil, nil, nil) 636 if err == unix.EINTR { 637 t.Log("Select interrupted") 638 continue 639 } else if err != nil { 640 t.Fatalf("Select: %v", err) 641 } 642 if n != 1 { 643 t.Fatalf("Select: got %v ready file descriptors, expected 1", n) 644 } 645 break 646 } 647 } 648 649 func TestGetwd(t *testing.T) { 650 fd, err := os.Open(".") 651 if err != nil { 652 t.Fatalf("Open .: %s", err) 653 } 654 defer fd.Close() 655 // Directory list for test. Do not worry if any are symlinks or do not 656 // exist on some common unix desktop environments. That will be checked. 657 dirs := []string{"/", "/usr/bin", "/etc", "/var", "/opt"} 658 switch runtime.GOOS { 659 case "android": 660 dirs = []string{"/", "/system/bin"} 661 case "ios": 662 d1, err := ioutil.TempDir("", "d1") 663 if err != nil { 664 t.Fatalf("TempDir: %v", err) 665 } 666 d2, err := ioutil.TempDir("", "d2") 667 if err != nil { 668 t.Fatalf("TempDir: %v", err) 669 } 670 dirs = []string{d1, d2} 671 } 672 oldwd := os.Getenv("PWD") 673 for _, d := range dirs { 674 // Check whether d exists, is a dir and that d's path does not contain a symlink 675 fi, err := os.Stat(d) 676 if err != nil || !fi.IsDir() { 677 t.Logf("Test dir %s stat error (%v) or not a directory, skipping", d, err) 678 continue 679 } 680 check, err := filepath.EvalSymlinks(d) 681 if err != nil || check != d { 682 t.Logf("Test dir %s (%s) is symlink or other error (%v), skipping", d, check, err) 683 continue 684 } 685 err = os.Chdir(d) 686 if err != nil { 687 t.Fatalf("Chdir: %v", err) 688 } 689 pwd, err := unix.Getwd() 690 if err != nil { 691 t.Fatalf("Getwd in %s: %s", d, err) 692 } 693 os.Setenv("PWD", oldwd) 694 err = fd.Chdir() 695 if err != nil { 696 // We changed the current directory and cannot go back. 697 // Don't let the tests continue; they'll scribble 698 // all over some other directory. 699 fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err) 700 os.Exit(1) 701 } 702 if pwd != d { 703 t.Fatalf("Getwd returned %q want %q", pwd, d) 704 } 705 } 706 } 707 708 func compareStat_t(t *testing.T, otherStat string, st1, st2 *unix.Stat_t) { 709 if st2.Dev != st1.Dev { 710 t.Errorf("%s/Fstatat: got dev %v, expected %v", otherStat, st2.Dev, st1.Dev) 711 } 712 if st2.Ino != st1.Ino { 713 t.Errorf("%s/Fstatat: got ino %v, expected %v", otherStat, st2.Ino, st1.Ino) 714 } 715 if st2.Mode != st1.Mode { 716 t.Errorf("%s/Fstatat: got mode %v, expected %v", otherStat, st2.Mode, st1.Mode) 717 } 718 if st2.Uid != st1.Uid { 719 t.Errorf("%s/Fstatat: got uid %v, expected %v", otherStat, st2.Uid, st1.Uid) 720 } 721 if st2.Gid != st1.Gid { 722 t.Errorf("%s/Fstatat: got gid %v, expected %v", otherStat, st2.Gid, st1.Gid) 723 } 724 if st2.Size != st1.Size { 725 t.Errorf("%s/Fstatat: got size %v, expected %v", otherStat, st2.Size, st1.Size) 726 } 727 } 728 729 func TestFstatat(t *testing.T) { 730 defer chtmpdir(t)() 731 732 touch(t, "file1") 733 734 var st1 unix.Stat_t 735 err := unix.Stat("file1", &st1) 736 if err != nil { 737 t.Fatalf("Stat: %v", err) 738 } 739 740 var st2 unix.Stat_t 741 err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0) 742 if err != nil { 743 t.Fatalf("Fstatat: %v", err) 744 } 745 746 compareStat_t(t, "Stat", &st1, &st2) 747 748 err = os.Symlink("file1", "symlink1") 749 if err != nil { 750 t.Fatal(err) 751 } 752 753 err = unix.Lstat("symlink1", &st1) 754 if err != nil { 755 t.Fatalf("Lstat: %v", err) 756 } 757 758 err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW) 759 if err != nil { 760 t.Fatalf("Fstatat: %v", err) 761 } 762 763 compareStat_t(t, "Lstat", &st1, &st2) 764 } 765 766 func TestFchmodat(t *testing.T) { 767 defer chtmpdir(t)() 768 769 touch(t, "file1") 770 err := os.Symlink("file1", "symlink1") 771 if err != nil { 772 t.Fatal(err) 773 } 774 775 mode := os.FileMode(0444) 776 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), 0) 777 if err != nil { 778 t.Fatalf("Fchmodat: unexpected error: %v", err) 779 } 780 781 fi, err := os.Stat("file1") 782 if err != nil { 783 t.Fatal(err) 784 } 785 786 if fi.Mode() != mode { 787 t.Errorf("Fchmodat: failed to change file mode: expected %v, got %v", mode, fi.Mode()) 788 } 789 790 mode = os.FileMode(0644) 791 didChmodSymlink := true 792 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), unix.AT_SYMLINK_NOFOLLOW) 793 if err != nil { 794 if (runtime.GOOS == "android" || runtime.GOOS == "linux" || 795 runtime.GOOS == "solaris" || runtime.GOOS == "illumos") && err == unix.EOPNOTSUPP { 796 // Linux and Illumos don't support flags != 0 797 didChmodSymlink = false 798 } else { 799 t.Fatalf("Fchmodat: unexpected error: %v", err) 800 } 801 } 802 803 if !didChmodSymlink { 804 // Didn't change mode of the symlink. On Linux, the permissions 805 // of a symbolic link are always 0777 according to symlink(7) 806 mode = os.FileMode(0777) 807 } 808 809 var st unix.Stat_t 810 err = unix.Lstat("symlink1", &st) 811 if err != nil { 812 t.Fatal(err) 813 } 814 815 got := os.FileMode(st.Mode & 0777) 816 if got != mode { 817 t.Errorf("Fchmodat: failed to change symlink mode: expected %v, got %v", mode, got) 818 } 819 } 820 821 func TestMkdev(t *testing.T) { 822 major := uint32(42) 823 minor := uint32(7) 824 dev := unix.Mkdev(major, minor) 825 826 if unix.Major(dev) != major { 827 t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major) 828 } 829 if unix.Minor(dev) != minor { 830 t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor) 831 } 832 } 833 834 func TestPipe(t *testing.T) { 835 const s = "hello" 836 var pipes [2]int 837 err := unix.Pipe(pipes[:]) 838 if err != nil { 839 t.Fatalf("pipe: %v", err) 840 } 841 r := pipes[0] 842 w := pipes[1] 843 go func() { 844 n, err := unix.Write(w, []byte(s)) 845 if err != nil { 846 t.Errorf("bad write: %v", err) 847 return 848 } 849 if n != len(s) { 850 t.Errorf("bad write count: %d", n) 851 return 852 } 853 err = unix.Close(w) 854 if err != nil { 855 t.Errorf("bad close: %v", err) 856 return 857 } 858 }() 859 var buf [10 + len(s)]byte 860 n, err := unix.Read(r, buf[:]) 861 if err != nil { 862 t.Fatalf("bad read: %v", err) 863 } 864 if n != len(s) { 865 t.Fatalf("bad read count: %d", n) 866 } 867 if string(buf[:n]) != s { 868 t.Fatalf("bad contents: %s", string(buf[:n])) 869 } 870 err = unix.Close(r) 871 if err != nil { 872 t.Fatalf("bad close: %v", err) 873 } 874 } 875 876 func TestRenameat(t *testing.T) { 877 defer chtmpdir(t)() 878 879 from, to := "renamefrom", "renameto" 880 881 touch(t, from) 882 883 err := unix.Renameat(unix.AT_FDCWD, from, unix.AT_FDCWD, to) 884 if err != nil { 885 t.Fatalf("Renameat: unexpected error: %v", err) 886 } 887 888 _, err = os.Stat(to) 889 if err != nil { 890 t.Error(err) 891 } 892 893 _, err = os.Stat(from) 894 if err == nil { 895 t.Errorf("Renameat: stat of renamed file %q unexpectedly succeeded", from) 896 } 897 } 898 899 func TestUtimesNanoAt(t *testing.T) { 900 defer chtmpdir(t)() 901 902 symlink := "symlink1" 903 os.Remove(symlink) 904 err := os.Symlink("nonexisting", symlink) 905 if err != nil { 906 t.Fatal(err) 907 } 908 909 // Some filesystems only support microsecond resolution. Account for 910 // that in Nsec. 911 ts := []unix.Timespec{ 912 {Sec: 1111, Nsec: 2000}, 913 {Sec: 3333, Nsec: 4000}, 914 } 915 err = unix.UtimesNanoAt(unix.AT_FDCWD, symlink, ts, unix.AT_SYMLINK_NOFOLLOW) 916 if err != nil { 917 t.Fatalf("UtimesNanoAt: %v", err) 918 } 919 920 var st unix.Stat_t 921 err = unix.Lstat(symlink, &st) 922 if err != nil { 923 t.Fatalf("Lstat: %v", err) 924 } 925 926 // Only check Mtim, Atim might not be supported by the underlying filesystem 927 expected := ts[1] 928 if st.Mtim.Nsec == 0 { 929 // Some filesystems only support 1-second time stamp resolution 930 // and will always set Nsec to 0. 931 expected.Nsec = 0 932 } 933 if st.Mtim != expected { 934 t.Errorf("UtimesNanoAt: wrong mtime: got %v, expected %v", st.Mtim, expected) 935 } 936 } 937 938 func TestSend(t *testing.T) { 939 ec := make(chan error, 2) 940 ts := []byte("HELLO GOPHER") 941 942 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 943 if err != nil { 944 t.Fatalf("Socketpair: %v", err) 945 } 946 defer unix.Close(fds[0]) 947 defer unix.Close(fds[1]) 948 949 go func() { 950 data := make([]byte, len(ts)) 951 952 _, _, err := unix.Recvfrom(fds[1], data, 0) 953 if err != nil { 954 ec <- err 955 } 956 if !bytes.Equal(ts, data) { 957 ec <- fmt.Errorf("data sent != data received. Received %q", data) 958 } 959 ec <- nil 960 }() 961 err = unix.Send(fds[0], ts, 0) 962 if err != nil { 963 ec <- err 964 } 965 966 select { 967 case err = <-ec: 968 if err != nil { 969 t.Fatalf("Send: %v", err) 970 } 971 case <-time.After(2 * time.Second): 972 t.Fatal("Send: nothing received after 2 seconds") 973 } 974 } 975 976 func TestSendmsgBuffers(t *testing.T) { 977 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 978 if err != nil { 979 t.Fatal(err) 980 } 981 defer unix.Close(fds[0]) 982 defer unix.Close(fds[1]) 983 984 var wg sync.WaitGroup 985 wg.Add(1) 986 go func() { 987 defer wg.Done() 988 bufs := [][]byte{ 989 make([]byte, 5), 990 nil, 991 make([]byte, 5), 992 } 993 n, oobn, recvflags, _, err := unix.RecvmsgBuffers(fds[1], bufs, nil, 0) 994 if err != nil { 995 t.Error(err) 996 return 997 } 998 if n != 10 { 999 t.Errorf("got %d bytes, want 10", n) 1000 } 1001 if oobn != 0 { 1002 t.Errorf("got %d OOB bytes, want 0", oobn) 1003 } 1004 if recvflags != 0 { 1005 t.Errorf("got flags %#x, want %#x", recvflags, 0) 1006 } 1007 want := [][]byte{ 1008 []byte("01234"), 1009 nil, 1010 []byte("56789"), 1011 } 1012 if !reflect.DeepEqual(bufs, want) { 1013 t.Errorf("got data %q, want %q", bufs, want) 1014 } 1015 }() 1016 1017 defer wg.Wait() 1018 1019 bufs := [][]byte{ 1020 []byte("012"), 1021 []byte("34"), 1022 nil, 1023 []byte("5678"), 1024 []byte("9"), 1025 } 1026 n, err := unix.SendmsgBuffers(fds[0], bufs, nil, nil, 0) 1027 if err != nil { 1028 t.Fatal(err) 1029 } 1030 if n != 10 { 1031 t.Errorf("sent %d bytes, want 10", n) 1032 } 1033 } 1034 1035 // Issue 56384. 1036 func TestRecvmsgControl(t *testing.T) { 1037 switch runtime.GOOS { 1038 case "solaris", "illumos": 1039 // Test fails on Solaris, saying 1040 // "got 0 control messages, want 1". 1041 // Not sure why; Solaris recvmsg man page says 1042 // "For processes on the same host, recvmsg() can be 1043 // used to receive a file descriptor from another 1044 // process, but it cannot receive ancillary data." 1045 t.Skipf("skipping on %s", runtime.GOOS) 1046 } 1047 1048 fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0) 1049 if err != nil { 1050 t.Fatal(err) 1051 } 1052 defer unix.Close(fds[0]) 1053 defer unix.Close(fds[1]) 1054 1055 const payload = "hello" 1056 1057 // Start a goroutine that sends a control message followed by 1058 // a payload on fds[1]. 1059 go func() { 1060 f, err := os.Create(filepath.Join(t.TempDir(), "file")) 1061 if err != nil { 1062 t.Error(err) 1063 return 1064 } 1065 defer f.Close() 1066 1067 rc, err := f.SyscallConn() 1068 if err != nil { 1069 t.Error(err) 1070 return 1071 } 1072 var rights []byte 1073 err = rc.Control(func(fd uintptr) { 1074 rights = unix.UnixRights(int(fd)) 1075 }) 1076 if err != nil { 1077 t.Error(err) 1078 return 1079 } 1080 1081 _, err = unix.SendmsgN(fds[1], nil, rights, nil, 0) 1082 if err != nil { 1083 t.Error(err) 1084 } 1085 if _, err := unix.Write(fds[1], []byte(payload)); err != nil { 1086 t.Error(err) 1087 } 1088 }() 1089 1090 // Read the control message sent by the goroutine. The 1091 // goroutine writes to fds[1], we read from fds[0]. 1092 1093 cbuf := make([]byte, unix.CmsgSpace(4)) 1094 _, cn, _, _, err := unix.Recvmsg(fds[0], nil, cbuf, 0) 1095 if err != nil { 1096 t.Fatal(err) 1097 } 1098 cbuf = cbuf[:cn] 1099 1100 // Read the payload sent by the goroutine. 1101 1102 buf := make([]byte, len(payload)) 1103 n, err := unix.Read(fds[0], buf) 1104 if err != nil { 1105 t.Fatal(err) 1106 } 1107 buf = buf[:n] 1108 if payload != string(buf) { 1109 t.Errorf("read payload %q, want %q", buf, payload) 1110 } 1111 1112 // Check the control message. 1113 1114 cmsgs, err := unix.ParseSocketControlMessage(cbuf) 1115 if err != nil { 1116 t.Fatal(err) 1117 } 1118 if len(cmsgs) != 1 { 1119 t.Fatalf("got %d control messages, want 1", len(cmsgs)) 1120 } 1121 cfds, err := unix.ParseUnixRights(&cmsgs[0]) 1122 if err != nil { 1123 t.Fatal(err) 1124 } 1125 if len(cfds) != 1 { 1126 t.Fatalf("got %d fds, want 1", len(cfds)) 1127 } 1128 defer unix.Close(cfds[0]) 1129 } 1130 1131 // mktmpfifo creates a temporary FIFO and provides a cleanup function. 1132 func mktmpfifo(t *testing.T) (*os.File, func()) { 1133 err := unix.Mkfifo("fifo", 0666) 1134 if err != nil { 1135 t.Fatalf("mktmpfifo: failed to create FIFO: %v", err) 1136 } 1137 1138 f, err := os.OpenFile("fifo", os.O_RDWR, 0666) 1139 if err != nil { 1140 os.Remove("fifo") 1141 t.Fatalf("mktmpfifo: failed to open FIFO: %v", err) 1142 } 1143 1144 return f, func() { 1145 f.Close() 1146 os.Remove("fifo") 1147 } 1148 } 1149 1150 // utilities taken from os/os_test.go 1151 1152 func touch(t *testing.T, name string) { 1153 f, err := os.Create(name) 1154 if err != nil { 1155 t.Fatal(err) 1156 } 1157 if err := f.Close(); err != nil { 1158 t.Fatal(err) 1159 } 1160 } 1161 1162 // chtmpdir changes the working directory to a new temporary directory and 1163 // provides a cleanup function. Used when PWD is read-only. 1164 func chtmpdir(t *testing.T) func() { 1165 oldwd, err := os.Getwd() 1166 if err != nil { 1167 t.Fatalf("chtmpdir: %v", err) 1168 } 1169 d, err := ioutil.TempDir("", "test") 1170 if err != nil { 1171 t.Fatalf("chtmpdir: %v", err) 1172 } 1173 if err := os.Chdir(d); err != nil { 1174 t.Fatalf("chtmpdir: %v", err) 1175 } 1176 return func() { 1177 if err := os.Chdir(oldwd); err != nil { 1178 t.Fatalf("chtmpdir: %v", err) 1179 } 1180 os.RemoveAll(d) 1181 } 1182 }