gopkg.in/gf.v1@v1.8.5/third/golang.org/x/sys/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 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package unix_test 8 9 import ( 10 "flag" 11 "fmt" 12 "io/ioutil" 13 "net" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "runtime" 18 "syscall" 19 "testing" 20 "time" 21 22 "github.com/gogf/gf/third/golang.org/x/sys/unix" 23 ) 24 25 // Tests that below functions, structures and constants are consistent 26 // on all Unix-like systems. 27 func _() { 28 // program scheduling priority functions and constants 29 var ( 30 _ func(int, int, int) error = unix.Setpriority 31 _ func(int, int) (int, error) = unix.Getpriority 32 ) 33 const ( 34 _ int = unix.PRIO_USER 35 _ int = unix.PRIO_PROCESS 36 _ int = unix.PRIO_PGRP 37 ) 38 39 // termios constants 40 const ( 41 _ int = unix.TCIFLUSH 42 _ int = unix.TCIOFLUSH 43 _ int = unix.TCOFLUSH 44 ) 45 46 // fcntl file locking structure and constants 47 var ( 48 _ = unix.Flock_t{ 49 Type: int16(0), 50 Whence: int16(0), 51 Start: int64(0), 52 Len: int64(0), 53 Pid: int32(0), 54 } 55 ) 56 const ( 57 _ = unix.F_GETLK 58 _ = unix.F_SETLK 59 _ = unix.F_SETLKW 60 ) 61 } 62 63 func TestErrnoSignalName(t *testing.T) { 64 testErrors := []struct { 65 num syscall.Errno 66 name string 67 }{ 68 {syscall.EPERM, "EPERM"}, 69 {syscall.EINVAL, "EINVAL"}, 70 {syscall.ENOENT, "ENOENT"}, 71 } 72 73 for _, te := range testErrors { 74 t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) { 75 e := unix.ErrnoName(te.num) 76 if e != te.name { 77 t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name) 78 } 79 }) 80 } 81 82 testSignals := []struct { 83 num syscall.Signal 84 name string 85 }{ 86 {syscall.SIGHUP, "SIGHUP"}, 87 {syscall.SIGPIPE, "SIGPIPE"}, 88 {syscall.SIGSEGV, "SIGSEGV"}, 89 } 90 91 for _, ts := range testSignals { 92 t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) { 93 s := unix.SignalName(ts.num) 94 if s != ts.name { 95 t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name) 96 } 97 }) 98 } 99 } 100 101 func TestFcntlInt(t *testing.T) { 102 t.Parallel() 103 file, err := ioutil.TempFile("", "TestFnctlInt") 104 if err != nil { 105 t.Fatal(err) 106 } 107 defer os.Remove(file.Name()) 108 defer file.Close() 109 f := file.Fd() 110 flags, err := unix.FcntlInt(f, unix.F_GETFD, 0) 111 if err != nil { 112 t.Fatal(err) 113 } 114 if flags&unix.FD_CLOEXEC == 0 { 115 t.Errorf("flags %#x do not include FD_CLOEXEC", flags) 116 } 117 } 118 119 // TestFcntlFlock tests whether the file locking structure matches 120 // the calling convention of each kernel. 121 func TestFcntlFlock(t *testing.T) { 122 name := filepath.Join(os.TempDir(), "TestFcntlFlock") 123 fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) 124 if err != nil { 125 t.Fatalf("Open failed: %v", err) 126 } 127 defer unix.Unlink(name) 128 defer unix.Close(fd) 129 flock := unix.Flock_t{ 130 Type: unix.F_RDLCK, 131 Start: 0, Len: 0, Whence: 1, 132 } 133 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { 134 t.Fatalf("FcntlFlock failed: %v", err) 135 } 136 } 137 138 // TestPassFD tests passing a file descriptor over a Unix socket. 139 // 140 // This test involved both a parent and child process. The parent 141 // process is invoked as a normal test, with "go test", which then 142 // runs the child process by running the current test binary with args 143 // "-test.run=^TestPassFD$" and an environment variable used to signal 144 // that the test should become the child process instead. 145 func TestPassFD(t *testing.T) { 146 if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 147 t.Skip("cannot exec subprocess on iOS, skipping test") 148 } 149 if runtime.GOOS == "aix" { 150 t.Skip("getsockname issue on AIX 7.2 tl1, skipping test") 151 } 152 153 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 154 passFDChild() 155 return 156 } 157 158 tempDir, err := ioutil.TempDir("", "TestPassFD") 159 if err != nil { 160 t.Fatal(err) 161 } 162 defer os.RemoveAll(tempDir) 163 164 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 165 if err != nil { 166 t.Fatalf("Socketpair: %v", err) 167 } 168 defer unix.Close(fds[0]) 169 defer unix.Close(fds[1]) 170 writeFile := os.NewFile(uintptr(fds[0]), "child-writes") 171 readFile := os.NewFile(uintptr(fds[1]), "parent-reads") 172 defer writeFile.Close() 173 defer readFile.Close() 174 175 cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) 176 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 177 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { 178 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) 179 } 180 cmd.ExtraFiles = []*os.File{writeFile} 181 182 out, err := cmd.CombinedOutput() 183 if len(out) > 0 || err != nil { 184 t.Fatalf("child process: %q, %v", out, err) 185 } 186 187 c, err := net.FileConn(readFile) 188 if err != nil { 189 t.Fatalf("FileConn: %v", err) 190 } 191 defer c.Close() 192 193 uc, ok := c.(*net.UnixConn) 194 if !ok { 195 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) 196 } 197 198 buf := make([]byte, 32) // expect 1 byte 199 oob := make([]byte, 32) // expect 24 bytes 200 closeUnix := time.AfterFunc(5*time.Second, func() { 201 t.Logf("timeout reading from unix socket") 202 uc.Close() 203 }) 204 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) 205 if err != nil { 206 t.Fatalf("ReadMsgUnix: %v", err) 207 } 208 closeUnix.Stop() 209 210 scms, err := unix.ParseSocketControlMessage(oob[:oobn]) 211 if err != nil { 212 t.Fatalf("ParseSocketControlMessage: %v", err) 213 } 214 if len(scms) != 1 { 215 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) 216 } 217 scm := scms[0] 218 gotFds, err := unix.ParseUnixRights(&scm) 219 if err != nil { 220 t.Fatalf("unix.ParseUnixRights: %v", err) 221 } 222 if len(gotFds) != 1 { 223 t.Fatalf("wanted 1 fd; got %#v", gotFds) 224 } 225 226 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") 227 defer f.Close() 228 229 got, err := ioutil.ReadAll(f) 230 want := "Hello from child process!\n" 231 if string(got) != want { 232 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) 233 } 234 } 235 236 // passFDChild is the child process used by TestPassFD. 237 func passFDChild() { 238 defer os.Exit(0) 239 240 // Look for our fd. It should be fd 3, but we work around an fd leak 241 // bug here (http://golang.org/issue/2603) to let it be elsewhere. 242 var uc *net.UnixConn 243 for fd := uintptr(3); fd <= 10; fd++ { 244 f := os.NewFile(fd, "unix-conn") 245 var ok bool 246 netc, _ := net.FileConn(f) 247 uc, ok = netc.(*net.UnixConn) 248 if ok { 249 break 250 } 251 } 252 if uc == nil { 253 fmt.Println("failed to find unix fd") 254 return 255 } 256 257 // Make a file f to send to our parent process on uc. 258 // We make it in tempDir, which our parent will clean up. 259 flag.Parse() 260 tempDir := flag.Arg(0) 261 f, err := ioutil.TempFile(tempDir, "") 262 if err != nil { 263 fmt.Printf("TempFile: %v", err) 264 return 265 } 266 267 f.Write([]byte("Hello from child process!\n")) 268 f.Seek(0, 0) 269 270 rights := unix.UnixRights(int(f.Fd())) 271 dummyByte := []byte("x") 272 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) 273 if err != nil { 274 fmt.Printf("WriteMsgUnix: %v", err) 275 return 276 } 277 if n != 1 || oobn != len(rights) { 278 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) 279 return 280 } 281 } 282 283 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, 284 // and ParseUnixRights are able to successfully round-trip lists of file descriptors. 285 func TestUnixRightsRoundtrip(t *testing.T) { 286 testCases := [...][][]int{ 287 {{42}}, 288 {{1, 2}}, 289 {{3, 4, 5}}, 290 {{}}, 291 {{1, 2}, {3, 4, 5}, {}, {7}}, 292 } 293 for _, testCase := range testCases { 294 b := []byte{} 295 var n int 296 for _, fds := range testCase { 297 // Last assignment to n wins 298 n = len(b) + unix.CmsgLen(4*len(fds)) 299 b = append(b, unix.UnixRights(fds...)...) 300 } 301 // Truncate b 302 b = b[:n] 303 304 scms, err := unix.ParseSocketControlMessage(b) 305 if err != nil { 306 t.Fatalf("ParseSocketControlMessage: %v", err) 307 } 308 if len(scms) != len(testCase) { 309 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) 310 } 311 for i, scm := range scms { 312 gotFds, err := unix.ParseUnixRights(&scm) 313 if err != nil { 314 t.Fatalf("ParseUnixRights: %v", err) 315 } 316 wantFds := testCase[i] 317 if len(gotFds) != len(wantFds) { 318 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) 319 } 320 for j, fd := range gotFds { 321 if fd != wantFds[j] { 322 t.Fatalf("expected fd %v, got %v", wantFds[j], fd) 323 } 324 } 325 } 326 } 327 } 328 329 func TestRlimit(t *testing.T) { 330 var rlimit, zero unix.Rlimit 331 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) 332 if err != nil { 333 t.Fatalf("Getrlimit: save failed: %v", err) 334 } 335 if zero == rlimit { 336 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) 337 } 338 set := rlimit 339 set.Cur = set.Max - 1 340 if runtime.GOOS == "darwin" && set.Cur > 10240 { 341 // The max file limit is 10240, even though 342 // the max returned by Getrlimit is 1<<63-1. 343 // This is OPEN_MAX in sys/syslimits.h. 344 set.Cur = 10240 345 } 346 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) 347 if err != nil { 348 t.Fatalf("Setrlimit: set failed: %#v %v", set, err) 349 } 350 var get unix.Rlimit 351 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) 352 if err != nil { 353 t.Fatalf("Getrlimit: get failed: %v", err) 354 } 355 set = rlimit 356 set.Cur = set.Max - 1 357 if set != get { 358 // Seems like Darwin requires some privilege to 359 // increase the soft limit of rlimit sandbox, though 360 // Setrlimit never reports an error. 361 switch runtime.GOOS { 362 case "darwin": 363 default: 364 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) 365 } 366 } 367 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) 368 if err != nil { 369 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) 370 } 371 } 372 373 func TestSeekFailure(t *testing.T) { 374 _, err := unix.Seek(-1, 0, 0) 375 if err == nil { 376 t.Fatalf("Seek(-1, 0, 0) did not fail") 377 } 378 str := err.Error() // used to crash on Linux 379 t.Logf("Seek: %v", str) 380 if str == "" { 381 t.Fatalf("Seek(-1, 0, 0) return error with empty message") 382 } 383 } 384 385 func TestDup(t *testing.T) { 386 file, err := ioutil.TempFile("", "TestDup") 387 if err != nil { 388 t.Fatalf("Tempfile failed: %v", err) 389 } 390 defer os.Remove(file.Name()) 391 defer file.Close() 392 f := int(file.Fd()) 393 394 newFd, err := unix.Dup(f) 395 if err != nil { 396 t.Fatalf("Dup: %v", err) 397 } 398 399 err = unix.Dup2(newFd, newFd+1) 400 if err != nil { 401 t.Fatalf("Dup2: %v", err) 402 } 403 404 b1 := []byte("Test123") 405 b2 := make([]byte, 7) 406 _, err = unix.Write(newFd+1, b1) 407 if err != nil { 408 t.Fatalf("Write to dup2 fd failed: %v", err) 409 } 410 _, err = unix.Seek(f, 0, 0) 411 if err != nil { 412 t.Fatalf("Seek failed: %v", err) 413 } 414 _, err = unix.Read(f, b2) 415 if err != nil { 416 t.Fatalf("Read back failed: %v", err) 417 } 418 if string(b1) != string(b2) { 419 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) 420 } 421 } 422 423 func TestPoll(t *testing.T) { 424 if runtime.GOOS == "android" || 425 (runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")) { 426 t.Skip("mkfifo syscall is not available on android and iOS, skipping test") 427 } 428 429 f, cleanup := mktmpfifo(t) 430 defer cleanup() 431 432 const timeout = 100 433 434 ok := make(chan bool, 1) 435 go func() { 436 select { 437 case <-time.After(10 * timeout * time.Millisecond): 438 t.Errorf("Poll: failed to timeout after %d milliseconds", 10*timeout) 439 case <-ok: 440 } 441 }() 442 443 fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}} 444 n, err := unix.Poll(fds, timeout) 445 ok <- true 446 if err != nil { 447 t.Errorf("Poll: unexpected error: %v", err) 448 return 449 } 450 if n != 0 { 451 t.Errorf("Poll: wrong number of events: got %v, expected %v", n, 0) 452 return 453 } 454 } 455 456 func TestGetwd(t *testing.T) { 457 fd, err := os.Open(".") 458 if err != nil { 459 t.Fatalf("Open .: %s", err) 460 } 461 defer fd.Close() 462 // Directory list for test. Do not worry if any are symlinks or do not 463 // exist on some common unix desktop environments. That will be checked. 464 dirs := []string{"/", "/usr/bin", "/etc", "/var", "/opt"} 465 switch runtime.GOOS { 466 case "android": 467 dirs = []string{"/", "/system/bin"} 468 case "darwin": 469 switch runtime.GOARCH { 470 case "arm", "arm64": 471 d1, err := ioutil.TempDir("", "d1") 472 if err != nil { 473 t.Fatalf("TempDir: %v", err) 474 } 475 d2, err := ioutil.TempDir("", "d2") 476 if err != nil { 477 t.Fatalf("TempDir: %v", err) 478 } 479 dirs = []string{d1, d2} 480 } 481 } 482 oldwd := os.Getenv("PWD") 483 for _, d := range dirs { 484 // Check whether d exists, is a dir and that d's path does not contain a symlink 485 fi, err := os.Stat(d) 486 if err != nil || !fi.IsDir() { 487 t.Logf("Test dir %s stat error (%v) or not a directory, skipping", d, err) 488 continue 489 } 490 check, err := filepath.EvalSymlinks(d) 491 if err != nil || check != d { 492 t.Logf("Test dir %s (%s) is symlink or other error (%v), skipping", d, check, err) 493 continue 494 } 495 err = os.Chdir(d) 496 if err != nil { 497 t.Fatalf("Chdir: %v", err) 498 } 499 pwd, err := unix.Getwd() 500 if err != nil { 501 t.Fatalf("Getwd in %s: %s", d, err) 502 } 503 os.Setenv("PWD", oldwd) 504 err = fd.Chdir() 505 if err != nil { 506 // We changed the current directory and cannot go back. 507 // Don't let the tests continue; they'll scribble 508 // all over some other directory. 509 fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err) 510 os.Exit(1) 511 } 512 if pwd != d { 513 t.Fatalf("Getwd returned %q want %q", pwd, d) 514 } 515 } 516 } 517 518 func TestFstatat(t *testing.T) { 519 defer chtmpdir(t)() 520 521 touch(t, "file1") 522 523 var st1 unix.Stat_t 524 err := unix.Stat("file1", &st1) 525 if err != nil { 526 t.Fatalf("Stat: %v", err) 527 } 528 529 var st2 unix.Stat_t 530 err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0) 531 if err != nil { 532 t.Fatalf("Fstatat: %v", err) 533 } 534 535 if st1 != st2 { 536 t.Errorf("Fstatat: returned stat does not match Stat") 537 } 538 539 err = os.Symlink("file1", "symlink1") 540 if err != nil { 541 t.Fatal(err) 542 } 543 544 err = unix.Lstat("symlink1", &st1) 545 if err != nil { 546 t.Fatalf("Lstat: %v", err) 547 } 548 549 err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW) 550 if err != nil { 551 t.Fatalf("Fstatat: %v", err) 552 } 553 554 if st1 != st2 { 555 t.Errorf("Fstatat: returned stat does not match Lstat") 556 } 557 } 558 559 func TestFchmodat(t *testing.T) { 560 defer chtmpdir(t)() 561 562 touch(t, "file1") 563 err := os.Symlink("file1", "symlink1") 564 if err != nil { 565 t.Fatal(err) 566 } 567 568 mode := os.FileMode(0444) 569 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), 0) 570 if err != nil { 571 t.Fatalf("Fchmodat: unexpected error: %v", err) 572 } 573 574 fi, err := os.Stat("file1") 575 if err != nil { 576 t.Fatal(err) 577 } 578 579 if fi.Mode() != mode { 580 t.Errorf("Fchmodat: failed to change file mode: expected %v, got %v", mode, fi.Mode()) 581 } 582 583 mode = os.FileMode(0644) 584 didChmodSymlink := true 585 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), unix.AT_SYMLINK_NOFOLLOW) 586 if err != nil { 587 if (runtime.GOOS == "android" || runtime.GOOS == "linux" || runtime.GOOS == "solaris") && err == unix.EOPNOTSUPP { 588 // Linux and Illumos don't support flags != 0 589 didChmodSymlink = false 590 } else { 591 t.Fatalf("Fchmodat: unexpected error: %v", err) 592 } 593 } 594 595 if !didChmodSymlink { 596 // Didn't change mode of the symlink. On Linux, the permissions 597 // of a symbolic link are always 0777 according to symlink(7) 598 mode = os.FileMode(0777) 599 } 600 601 var st unix.Stat_t 602 err = unix.Lstat("symlink1", &st) 603 if err != nil { 604 t.Fatal(err) 605 } 606 607 got := os.FileMode(st.Mode & 0777) 608 if got != mode { 609 t.Errorf("Fchmodat: failed to change symlink mode: expected %v, got %v", mode, got) 610 } 611 } 612 613 func TestMkdev(t *testing.T) { 614 major := uint32(42) 615 minor := uint32(7) 616 dev := unix.Mkdev(major, minor) 617 618 if unix.Major(dev) != major { 619 t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major) 620 } 621 if unix.Minor(dev) != minor { 622 t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor) 623 } 624 } 625 626 func TestRenameat(t *testing.T) { 627 defer chtmpdir(t)() 628 629 from, to := "renamefrom", "renameto" 630 631 touch(t, from) 632 633 err := unix.Renameat(unix.AT_FDCWD, from, unix.AT_FDCWD, to) 634 if err != nil { 635 t.Fatalf("Renameat: unexpected error: %v", err) 636 } 637 638 _, err = os.Stat(to) 639 if err != nil { 640 t.Error(err) 641 } 642 643 _, err = os.Stat(from) 644 if err == nil { 645 t.Errorf("Renameat: stat of renamed file %q unexpectedly suceeded", from) 646 } 647 } 648 649 // mktmpfifo creates a temporary FIFO and provides a cleanup function. 650 func mktmpfifo(t *testing.T) (*os.File, func()) { 651 err := unix.Mkfifo("fifo", 0666) 652 if err != nil { 653 t.Fatalf("mktmpfifo: failed to create FIFO: %v", err) 654 } 655 656 f, err := os.OpenFile("fifo", os.O_RDWR, 0666) 657 if err != nil { 658 os.Remove("fifo") 659 t.Fatalf("mktmpfifo: failed to open FIFO: %v", err) 660 } 661 662 return f, func() { 663 f.Close() 664 os.Remove("fifo") 665 } 666 } 667 668 // utilities taken from os/os_test.go 669 670 func touch(t *testing.T, name string) { 671 f, err := os.Create(name) 672 if err != nil { 673 t.Fatal(err) 674 } 675 if err := f.Close(); err != nil { 676 t.Fatal(err) 677 } 678 } 679 680 // chtmpdir changes the working directory to a new temporary directory and 681 // provides a cleanup function. Used when PWD is read-only. 682 func chtmpdir(t *testing.T) func() { 683 oldwd, err := os.Getwd() 684 if err != nil { 685 t.Fatalf("chtmpdir: %v", err) 686 } 687 d, err := ioutil.TempDir("", "test") 688 if err != nil { 689 t.Fatalf("chtmpdir: %v", err) 690 } 691 if err := os.Chdir(d); err != nil { 692 t.Fatalf("chtmpdir: %v", err) 693 } 694 return func() { 695 if err := os.Chdir(oldwd); err != nil { 696 t.Fatalf("chtmpdir: %v", err) 697 } 698 os.RemoveAll(d) 699 } 700 }