github.com/Kalvelign/golang-windows-sys-lib@v0.0.0-20221121121202-63da651435e1/unix/syscall_zos_test.go (about) 1 // Copyright 2020 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 zos && s390x 6 // +build zos,s390x 7 8 package unix_test 9 10 import ( 11 "flag" 12 "fmt" 13 "io/ioutil" 14 "net" 15 "os" 16 "os/exec" 17 "path/filepath" 18 "runtime" 19 "strconv" 20 "syscall" 21 "testing" 22 "time" 23 "unsafe" 24 25 "golang.org/x/sys/unix" 26 ) 27 28 // Tests that below functions, structures and constants are consistent 29 // on all Unix-like systems. 30 func _() { 31 // program scheduling priority functions and constants 32 var ( 33 _ func(int, int, int) error = unix.Setpriority 34 _ func(int, int) (int, error) = unix.Getpriority 35 ) 36 const ( 37 _ int = unix.PRIO_USER 38 _ int = unix.PRIO_PROCESS 39 _ int = unix.PRIO_PGRP 40 ) 41 42 // termios constants 43 const ( 44 _ int = unix.TCIFLUSH 45 _ int = unix.TCIOFLUSH 46 _ int = unix.TCOFLUSH 47 ) 48 49 // fcntl file locking structure and constants 50 var ( 51 _ = unix.Flock_t{ 52 Type: int16(0), 53 Whence: int16(0), 54 Start: int64(0), 55 Len: int64(0), 56 Pid: int32(0), 57 } 58 ) 59 const ( 60 _ = unix.F_GETLK 61 _ = unix.F_SETLK 62 _ = unix.F_SETLKW 63 ) 64 } 65 66 func TestErrnoSignalName(t *testing.T) { 67 testErrors := []struct { 68 num syscall.Errno 69 name string 70 }{ 71 {syscall.EPERM, "EDC5139I"}, 72 {syscall.EINVAL, "EDC5121I"}, 73 {syscall.ENOENT, "EDC5129I"}, 74 } 75 76 for _, te := range testErrors { 77 t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) { 78 e := unix.ErrnoName(te.num) 79 if e != te.name { 80 t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name) 81 } 82 }) 83 } 84 85 testSignals := []struct { 86 num syscall.Signal 87 name string 88 }{ 89 {syscall.SIGHUP, "SIGHUP"}, 90 {syscall.SIGPIPE, "SIGPIPE"}, 91 {syscall.SIGSEGV, "SIGSEGV"}, 92 } 93 94 for _, ts := range testSignals { 95 t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) { 96 s := unix.SignalName(ts.num) 97 if s != ts.name { 98 t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name) 99 } 100 }) 101 } 102 } 103 104 func TestSignalNum(t *testing.T) { 105 testSignals := []struct { 106 name string 107 want syscall.Signal 108 }{ 109 {"SIGHUP", syscall.SIGHUP}, 110 {"SIGPIPE", syscall.SIGPIPE}, 111 {"SIGSEGV", syscall.SIGSEGV}, 112 {"NONEXISTS", 0}, 113 } 114 for _, ts := range testSignals { 115 t.Run(fmt.Sprintf("%s/%d", ts.name, ts.want), func(t *testing.T) { 116 got := unix.SignalNum(ts.name) 117 if got != ts.want { 118 t.Errorf("SignalNum(%s) returned %d, want %d", ts.name, got, ts.want) 119 } 120 }) 121 122 } 123 } 124 125 func TestFcntlInt(t *testing.T) { 126 t.Parallel() 127 file, err := ioutil.TempFile("", "TestFnctlInt") 128 if err != nil { 129 t.Fatal(err) 130 } 131 defer os.Remove(file.Name()) 132 defer file.Close() 133 f := file.Fd() 134 flags, err := unix.FcntlInt(f, unix.F_GETFD, 0) 135 if err != nil { 136 t.Fatal(err) 137 } 138 if flags&unix.FD_CLOEXEC == 0 { 139 t.Errorf("flags %#x do not include FD_CLOEXEC", flags) 140 } 141 } 142 143 // TestFcntlFlock tests whether the file locking structure matches 144 // the calling convention of each kernel. 145 func TestFcntlFlock(t *testing.T) { 146 name := filepath.Join(os.TempDir(), "TestFcntlFlock") 147 fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) 148 if err != nil { 149 t.Fatalf("Open failed: %v", err) 150 } 151 defer unix.Unlink(name) 152 defer unix.Close(fd) 153 flock := unix.Flock_t{ 154 Type: unix.F_RDLCK, 155 Start: 0, Len: 0, Whence: 1, 156 } 157 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { 158 t.Fatalf("FcntlFlock failed: %v", err) 159 } 160 } 161 162 // TestPassFD tests passing a file descriptor over a Unix socket. 163 // 164 // This test involved both a parent and child process. The parent 165 // process is invoked as a normal test, with "go test", which then 166 // runs the child process by running the current test binary with args 167 // "-test.run=^TestPassFD$" and an environment variable used to signal 168 // that the test should become the child process instead. 169 func TestPassFD(t *testing.T) { 170 if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { 171 t.Skip("cannot exec subprocess on iOS, skipping test") 172 } 173 174 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 175 passFDChild() 176 return 177 } 178 179 if runtime.GOOS == "aix" { 180 // Unix network isn't properly working on AIX 181 // 7.2 with Technical Level < 2 182 out, err := exec.Command("oslevel", "-s").Output() 183 if err != nil { 184 t.Skipf("skipping on AIX because oslevel -s failed: %v", err) 185 } 186 187 if len(out) < len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM 188 t.Skip("skipping on AIX because oslevel -s hasn't the right length") 189 } 190 aixVer := string(out[:4]) 191 tl, err := strconv.Atoi(string(out[5:7])) 192 if err != nil { 193 t.Skipf("skipping on AIX because oslevel -s output cannot be parsed: %v", err) 194 } 195 if aixVer < "7200" || (aixVer == "7200" && tl < 2) { 196 t.Skip("skipped on AIX versions previous to 7.2 TL 2") 197 } 198 } 199 200 tempDir, err := ioutil.TempDir("", "TestPassFD") 201 if err != nil { 202 t.Fatal(err) 203 } 204 defer os.RemoveAll(tempDir) 205 206 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 207 if err != nil { 208 t.Fatalf("Socketpair: %v", err) 209 } 210 writeFile := os.NewFile(uintptr(fds[0]), "child-writes") 211 readFile := os.NewFile(uintptr(fds[1]), "parent-reads") 212 defer writeFile.Close() 213 defer readFile.Close() 214 215 cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) 216 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 217 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { 218 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) 219 } 220 cmd.ExtraFiles = []*os.File{writeFile} 221 222 out, err := cmd.CombinedOutput() 223 if len(out) > 0 || err != nil { 224 t.Fatalf("child process: %q, %v", out, err) 225 } 226 227 c, err := net.FileConn(readFile) 228 if err != nil { 229 t.Fatalf("FileConn: %v", err) 230 } 231 defer c.Close() 232 233 uc, ok := c.(*net.UnixConn) 234 if !ok { 235 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) 236 } 237 238 buf := make([]byte, 32) // expect 1 byte 239 oob := make([]byte, 32) // expect 24 bytes 240 closeUnix := time.AfterFunc(5*time.Second, func() { 241 t.Logf("timeout reading from unix socket") 242 uc.Close() 243 }) 244 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) 245 if err != nil { 246 t.Fatalf("ReadMsgUnix: %v", err) 247 } 248 closeUnix.Stop() 249 250 scms, err := unix.ParseSocketControlMessage(oob[:oobn]) 251 if err != nil { 252 t.Fatalf("ParseSocketControlMessage: %v", err) 253 } 254 if len(scms) != 1 { 255 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) 256 } 257 scm := scms[0] 258 gotFds, err := unix.ParseUnixRights(&scm) 259 if err != nil { 260 t.Fatalf("unix.ParseUnixRights: %v", err) 261 } 262 if len(gotFds) != 1 { 263 t.Fatalf("wanted 1 fd; got %#v", gotFds) 264 } 265 266 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") 267 defer f.Close() 268 269 got, err := ioutil.ReadAll(f) 270 want := "Hello from child process!\n" 271 if string(got) != want { 272 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) 273 } 274 } 275 276 // passFDChild is the child process used by TestPassFD. 277 func passFDChild() { 278 defer os.Exit(0) 279 280 // Look for our fd. It should be fd 3, but we work around an fd leak 281 // bug here (http://golang.org/issue/2603) to let it be elsewhere. 282 var uc *net.UnixConn 283 for fd := uintptr(3); fd <= 10; fd++ { 284 f := os.NewFile(fd, "unix-conn") 285 var ok bool 286 netc, _ := net.FileConn(f) 287 uc, ok = netc.(*net.UnixConn) 288 if ok { 289 break 290 } 291 } 292 if uc == nil { 293 fmt.Println("failed to find unix fd") 294 return 295 } 296 297 // Make a file f to send to our parent process on uc. 298 // We make it in tempDir, which our parent will clean up. 299 flag.Parse() 300 tempDir := flag.Arg(0) 301 f, err := ioutil.TempFile(tempDir, "") 302 if err != nil { 303 fmt.Printf("TempFile: %v", err) 304 return 305 } 306 307 f.Write([]byte("Hello from child process!\n")) 308 f.Seek(0, 0) 309 310 rights := unix.UnixRights(int(f.Fd())) 311 dummyByte := []byte("x") 312 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) 313 if err != nil { 314 fmt.Printf("WriteMsgUnix: %v", err) 315 return 316 } 317 if n != 1 || oobn != len(rights) { 318 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) 319 return 320 } 321 } 322 323 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, 324 // and ParseUnixRights are able to successfully round-trip lists of file descriptors. 325 func TestUnixRightsRoundtrip(t *testing.T) { 326 testCases := [...][][]int{ 327 {{42}}, 328 {{1, 2}}, 329 {{3, 4, 5}}, 330 {{}}, 331 {{1, 2}, {3, 4, 5}, {}, {7}}, 332 } 333 for _, testCase := range testCases { 334 b := []byte{} 335 var n int 336 for _, fds := range testCase { 337 // Last assignment to n wins 338 n = len(b) + unix.CmsgLen(4*len(fds)) 339 b = append(b, unix.UnixRights(fds...)...) 340 } 341 // Truncate b 342 b = b[:n] 343 344 scms, err := unix.ParseSocketControlMessage(b) 345 if err != nil { 346 t.Fatalf("ParseSocketControlMessage: %v", err) 347 } 348 if len(scms) != len(testCase) { 349 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) 350 } 351 for i, scm := range scms { 352 gotFds, err := unix.ParseUnixRights(&scm) 353 if err != nil { 354 t.Fatalf("ParseUnixRights: %v", err) 355 } 356 wantFds := testCase[i] 357 if len(gotFds) != len(wantFds) { 358 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) 359 } 360 for j, fd := range gotFds { 361 if fd != wantFds[j] { 362 t.Fatalf("expected fd %v, got %v", wantFds[j], fd) 363 } 364 } 365 } 366 } 367 } 368 369 func TestRlimit(t *testing.T) { 370 var rlimit, zero unix.Rlimit 371 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) 372 if err != nil { 373 t.Fatalf("Getrlimit: save failed: %v", err) 374 } 375 if zero == rlimit { 376 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) 377 } 378 set := rlimit 379 set.Cur = set.Max - 1 380 if runtime.GOOS == "darwin" && set.Cur > 10240 { 381 // The max file limit is 10240, even though 382 // the max returned by Getrlimit is 1<<63-1. 383 // This is OPEN_MAX in sys/syslimits.h. 384 set.Cur = 10240 385 } 386 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) 387 if err != nil { 388 t.Fatalf("Setrlimit: set failed: %#v %v", set, err) 389 } 390 var get unix.Rlimit 391 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) 392 if err != nil { 393 t.Fatalf("Getrlimit: get failed: %v", err) 394 } 395 set = rlimit 396 set.Cur = set.Max - 1 397 if set != get { 398 // Seems like Darwin requires some privilege to 399 // increase the soft limit of rlimit sandbox, though 400 // Setrlimit never reports an error. 401 switch runtime.GOOS { 402 case "darwin": 403 default: 404 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) 405 } 406 } 407 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) 408 if err != nil { 409 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) 410 } 411 } 412 413 func TestSeekFailure(t *testing.T) { 414 _, err := unix.Seek(-1, 0, 0) 415 if err == nil { 416 t.Fatalf("Seek(-1, 0, 0) did not fail") 417 } 418 str := err.Error() // used to crash on Linux 419 t.Logf("Seek: %v", str) 420 if str == "" { 421 t.Fatalf("Seek(-1, 0, 0) return error with empty message") 422 } 423 } 424 425 func TestSetsockoptString(t *testing.T) { 426 // should not panic on empty string, see issue #31277 427 err := unix.SetsockoptString(-1, 0, 0, "") 428 if err == nil { 429 t.Fatalf("SetsockoptString: did not fail") 430 } 431 } 432 433 func TestDup(t *testing.T) { 434 file, err := ioutil.TempFile("", "TestDup") 435 if err != nil { 436 t.Fatalf("Tempfile failed: %v", err) 437 } 438 defer os.Remove(file.Name()) 439 defer file.Close() 440 f := int(file.Fd()) 441 442 newFd, err := unix.Dup(f) 443 if err != nil { 444 t.Fatalf("Dup: %v", err) 445 } 446 447 // Create and reserve a file descriptor. 448 // Dup2 automatically closes it before reusing it. 449 nullFile, err := os.Open("/dev/null") 450 if err != nil { 451 t.Fatal(err) 452 } 453 dupFd := int(file.Fd()) 454 err = unix.Dup2(newFd, dupFd) 455 if err != nil { 456 t.Fatalf("Dup2: %v", err) 457 } 458 // Keep the dummy file open long enough to not be closed in 459 // its finalizer. 460 runtime.KeepAlive(nullFile) 461 462 b1 := []byte("Test123") 463 b2 := make([]byte, 7) 464 _, err = unix.Write(dupFd, b1) 465 if err != nil { 466 t.Fatalf("Write to dup2 fd failed: %v", err) 467 } 468 _, err = unix.Seek(f, 0, 0) 469 if err != nil { 470 t.Fatalf("Seek failed: %v", err) 471 } 472 _, err = unix.Read(f, b2) 473 if err != nil { 474 t.Fatalf("Read back failed: %v", err) 475 } 476 if string(b1) != string(b2) { 477 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) 478 } 479 } 480 481 func TestGetwd(t *testing.T) { 482 fd, err := os.Open(".") 483 if err != nil { 484 t.Fatalf("Open .: %s", err) 485 } 486 defer fd.Close() 487 // Directory list for test. Do not worry if any are symlinks or do not 488 // exist on some common unix desktop environments. That will be checked. 489 dirs := []string{"/", "/usr/bin", "/etc", "/var", "/opt"} 490 switch runtime.GOOS { 491 case "android": 492 dirs = []string{"/", "/system/bin"} 493 case "darwin": 494 switch runtime.GOARCH { 495 case "arm64": 496 d1, err := ioutil.TempDir("", "d1") 497 if err != nil { 498 t.Fatalf("TempDir: %v", err) 499 } 500 d2, err := ioutil.TempDir("", "d2") 501 if err != nil { 502 t.Fatalf("TempDir: %v", err) 503 } 504 dirs = []string{d1, d2} 505 } 506 } 507 oldwd := os.Getenv("PWD") 508 for _, d := range dirs { 509 // Check whether d exists, is a dir and that d's path does not contain a symlink 510 fi, err := os.Stat(d) 511 if err != nil || !fi.IsDir() { 512 t.Logf("Test dir %s stat error (%v) or not a directory, skipping", d, err) 513 continue 514 } 515 check, err := filepath.EvalSymlinks(d) 516 if err != nil || check != d { 517 t.Logf("Test dir %s (%s) is symlink or other error (%v), skipping", d, check, err) 518 continue 519 } 520 err = os.Chdir(d) 521 if err != nil { 522 t.Fatalf("Chdir: %v", err) 523 } 524 pwd, err := unix.Getwd() 525 if err != nil { 526 t.Fatalf("Getwd in %s: %s", d, err) 527 } 528 os.Setenv("PWD", oldwd) 529 err = fd.Chdir() 530 if err != nil { 531 // We changed the current directory and cannot go back. 532 // Don't let the tests continue; they'll scribble 533 // all over some other directory. 534 fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err) 535 os.Exit(1) 536 } 537 if pwd != d { 538 t.Fatalf("Getwd returned %q want %q", pwd, d) 539 } 540 } 541 } 542 543 func TestMkdev(t *testing.T) { 544 major := uint32(42) 545 minor := uint32(7) 546 dev := unix.Mkdev(major, minor) 547 548 if unix.Major(dev) != major { 549 t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major) 550 } 551 if unix.Minor(dev) != minor { 552 t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor) 553 } 554 } 555 556 // mktmpfifo creates a temporary FIFO and provides a cleanup function. 557 func mktmpfifo(t *testing.T) (*os.File, func()) { 558 err := unix.Mkfifo("fifo", 0666) 559 if err != nil { 560 t.Fatalf("mktmpfifo: failed to create FIFO: %v", err) 561 } 562 563 f, err := os.OpenFile("fifo", os.O_RDWR, 0666) 564 if err != nil { 565 os.Remove("fifo") 566 t.Fatalf("mktmpfifo: failed to open FIFO: %v", err) 567 } 568 569 return f, func() { 570 f.Close() 571 os.Remove("fifo") 572 } 573 } 574 575 // utilities taken from os/os_test.go 576 577 func touch(t *testing.T, name string) { 578 f, err := os.Create(name) 579 if err != nil { 580 t.Fatal(err) 581 } 582 if err := f.Close(); err != nil { 583 t.Fatal(err) 584 } 585 } 586 587 // chtmpdir changes the working directory to a new temporary directory and 588 // provides a cleanup function. Used when PWD is read-only. 589 func chtmpdir(t *testing.T) func() { 590 oldwd, err := os.Getwd() 591 if err != nil { 592 t.Fatalf("chtmpdir: %v", err) 593 } 594 d, err := ioutil.TempDir("", "test") 595 if err != nil { 596 t.Fatalf("chtmpdir: %v", err) 597 } 598 if err := os.Chdir(d); err != nil { 599 t.Fatalf("chtmpdir: %v", err) 600 } 601 return func() { 602 if err := os.Chdir(oldwd); err != nil { 603 t.Fatalf("chtmpdir: %v", err) 604 } 605 os.RemoveAll(d) 606 } 607 } 608 609 func TestMountUnmount(t *testing.T) { 610 // use an available fs 611 var buffer struct { 612 header unix.W_Mnth 613 fsinfo [64]unix.W_Mntent 614 } 615 fsCount, err := unix.W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer))) 616 if err != nil { 617 t.Fatalf("W_Getmntent_A returns with error: %s", err.Error()) 618 } else if fsCount == 0 { 619 t.Fatalf("W_Getmntent_A returns no entries") 620 } 621 var fs string 622 var fstype string 623 var mountpoint string 624 var available bool = false 625 for i := 0; i < fsCount; i++ { 626 err = unix.Unmount(unix.ByteSliceToString(buffer.fsinfo[i].Mountpoint[:]), unix.MTM_RDWR) 627 if err != nil { 628 // Unmount and Mount require elevated privilege 629 // If test is run without such permission, skip test 630 if err == unix.EPERM { 631 t.Logf("Permission denied for Unmount. Skipping test (Errno2: %X)", unix.Errno2()) 632 return 633 } else if err == unix.EBUSY { 634 continue 635 } else { 636 t.Fatalf("Unmount returns with error: %s", err.Error()) 637 } 638 } else { 639 available = true 640 fs = unix.ByteSliceToString(buffer.fsinfo[i].Fsname[:]) 641 fstype = unix.ByteSliceToString(buffer.fsinfo[i].Fstname[:]) 642 mountpoint = unix.ByteSliceToString(buffer.fsinfo[i].Mountpoint[:]) 643 t.Logf("using file system = %s; fstype = %s and mountpoint = %s\n", fs, fstype, mountpoint) 644 break 645 } 646 } 647 if !available { 648 t.Fatalf("No filesystem available") 649 } 650 // test unmount 651 buffer.header = unix.W_Mnth{} 652 fsCount, err = unix.W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer))) 653 if err != nil { 654 t.Fatalf("W_Getmntent_A returns with error: %s", err.Error()) 655 } 656 for i := 0; i < fsCount; i++ { 657 if unix.ByteSliceToString(buffer.fsinfo[i].Fsname[:]) == fs { 658 t.Fatalf("File system found after unmount") 659 } 660 } 661 // test mount 662 err = unix.Mount(fs, mountpoint, fstype, unix.MTM_RDWR, "") 663 if err != nil { 664 t.Fatalf("Mount returns with error: %s", err.Error()) 665 } 666 buffer.header = unix.W_Mnth{} 667 fsCount, err = unix.W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer))) 668 if err != nil { 669 t.Fatalf("W_Getmntent_A returns with error: %s", err.Error()) 670 } 671 fsMounted := false 672 for i := 0; i < fsCount; i++ { 673 if unix.ByteSliceToString(buffer.fsinfo[i].Fsname[:]) == fs && 674 unix.ByteSliceToString(buffer.fsinfo[i].Mountpoint[:]) == mountpoint { 675 fsMounted = true 676 } 677 } 678 if !fsMounted { 679 t.Fatalf("%s not mounted after Mount()", fs) 680 } 681 } 682 683 func TestChroot(t *testing.T) { 684 // create temp dir and tempfile 1 685 tempDir, err := ioutil.TempDir("", "TestChroot") 686 if err != nil { 687 t.Fatalf("TempDir: %s", err.Error()) 688 } 689 defer os.RemoveAll(tempDir) 690 f, err := ioutil.TempFile(tempDir, "chroot_test_file") 691 if err != nil { 692 t.Fatalf("TempFile: %s", err.Error()) 693 } 694 // chroot temp dir 695 err = unix.Chroot(tempDir) 696 // Chroot requires elevated privilege 697 // If test is run without such permission, skip test 698 if err == unix.EPERM { 699 t.Logf("Denied permission for Chroot. Skipping test (Errno2: %X)", unix.Errno2()) 700 return 701 } else if err != nil { 702 t.Fatalf("Chroot: %s", err.Error()) 703 } 704 // check if tempDir contains test file 705 files, err := ioutil.ReadDir("/") 706 if err != nil { 707 t.Fatalf("ReadDir: %s", err.Error()) 708 } 709 found := false 710 for _, file := range files { 711 if file.Name() == filepath.Base(f.Name()) { 712 found = true 713 break 714 } 715 } 716 if !found { 717 t.Fatalf("Temp file not found in temp dir") 718 } 719 } 720 721 func TestFlock(t *testing.T) { 722 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 723 defer os.Exit(0) 724 if len(os.Args) != 3 { 725 fmt.Printf("bad argument") 726 return 727 } 728 fn := os.Args[2] 729 f, err := os.OpenFile(fn, os.O_RDWR, 0755) 730 if err != nil { 731 fmt.Printf("%s", err.Error()) 732 return 733 } 734 err = unix.Flock(int(f.Fd()), unix.LOCK_EX|unix.LOCK_NB) 735 // if the lock we are trying should be locked, ignore EAGAIN error 736 // otherwise, report all errors 737 if err != nil && err != unix.EAGAIN { 738 fmt.Printf("%s", err.Error()) 739 } 740 } else { 741 // create temp dir and tempfile 1 742 tempDir, err := ioutil.TempDir("", "TestFlock") 743 if err != nil { 744 t.Fatalf("TempDir: %s", err.Error()) 745 } 746 defer os.RemoveAll(tempDir) 747 f, err := ioutil.TempFile(tempDir, "flock_test_file") 748 if err != nil { 749 t.Fatalf("TempFile: %s", err.Error()) 750 } 751 fd := int(f.Fd()) 752 753 /* Test Case 1 754 * Try acquiring an occupied lock from another process 755 */ 756 err = unix.Flock(fd, unix.LOCK_EX) 757 if err != nil { 758 t.Fatalf("Flock: %s", err.Error()) 759 } 760 cmd := exec.Command(os.Args[0], "-test.run=TestFlock", f.Name()) 761 cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") 762 out, err := cmd.CombinedOutput() 763 if len(out) > 0 || err != nil { 764 t.Fatalf("child process: %q, %v", out, err) 765 } 766 err = unix.Flock(fd, unix.LOCK_UN) 767 if err != nil { 768 t.Fatalf("Flock: %s", err.Error()) 769 } 770 771 /* Test Case 2 772 * Try locking with Flock and FcntlFlock for same file 773 */ 774 err = unix.Flock(fd, unix.LOCK_EX) 775 if err != nil { 776 t.Fatalf("Flock: %s", err.Error()) 777 } 778 flock := unix.Flock_t{ 779 Type: int16(unix.F_WRLCK), 780 Whence: int16(0), 781 Start: int64(0), 782 Len: int64(0), 783 Pid: int32(unix.Getppid()), 784 } 785 err = unix.FcntlFlock(f.Fd(), unix.F_SETLK, &flock) 786 if err != nil { 787 t.Fatalf("FcntlFlock: %s", err.Error()) 788 } 789 } 790 } 791 792 func TestSelect(t *testing.T) { 793 for { 794 n, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0}) 795 if err == unix.EINTR { 796 t.Logf("Select interrupted") 797 continue 798 } else if err != nil { 799 t.Fatalf("Select: %v", err) 800 } 801 if n != 0 { 802 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 803 } 804 break 805 } 806 807 dur := 250 * time.Millisecond 808 var took time.Duration 809 for { 810 // On some platforms (e.g. Linux), the passed-in timeval is 811 // updated by select(2). Make sure to reset to the full duration 812 // in case of an EINTR. 813 tv := unix.NsecToTimeval(int64(dur)) 814 start := time.Now() 815 n, err := unix.Select(0, nil, nil, nil, &tv) 816 took = time.Since(start) 817 if err == unix.EINTR { 818 t.Logf("Select interrupted after %v", took) 819 continue 820 } else if err != nil { 821 t.Fatalf("Select: %v", err) 822 } 823 if n != 0 { 824 t.Fatalf("Select: got %v ready file descriptors, expected 0", n) 825 } 826 break 827 } 828 829 // On some BSDs the actual timeout might also be slightly less than the requested. 830 // Add an acceptable margin to avoid flaky tests. 831 if took < dur*2/3 { 832 t.Errorf("Select: got %v timeout, expected at least %v", took, dur) 833 } 834 835 rr, ww, err := os.Pipe() 836 if err != nil { 837 t.Fatal(err) 838 } 839 defer rr.Close() 840 defer ww.Close() 841 842 if _, err := ww.Write([]byte("HELLO GOPHER")); err != nil { 843 t.Fatal(err) 844 } 845 846 rFdSet := &unix.FdSet{} 847 fd := int(rr.Fd()) 848 rFdSet.Set(fd) 849 850 for { 851 n, err := unix.Select(fd+1, rFdSet, nil, nil, nil) 852 if err == unix.EINTR { 853 t.Log("Select interrupted") 854 continue 855 } else if err != nil { 856 t.Fatalf("Select: %v", err) 857 } 858 if n != 1 { 859 t.Fatalf("Select: got %v ready file descriptors, expected 1", n) 860 } 861 break 862 } 863 }