2014-02-24 14:41:10 +09:00
|
|
|
// Copyright 2013 The Go Authors. All rights reserved.
|
2012-04-30 15:31:14 +10:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2022-03-03 18:23:35 -08:00
|
|
|
//go:build unix
|
2014-02-24 14:41:10 +09:00
|
|
|
|
2012-04-30 15:31:14 +10:00
|
|
|
package syscall_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
2015-06-05 11:01:53 -04:00
|
|
|
"internal/testenv"
|
2016-04-05 11:22:53 -07:00
|
|
|
"io"
|
2012-04-30 15:31:14 +10:00
|
|
|
"net"
|
|
|
|
|
"os"
|
|
|
|
|
"os/exec"
|
2014-02-24 20:35:01 +09:00
|
|
|
"path/filepath"
|
2013-08-24 01:51:25 +10:00
|
|
|
"runtime"
|
2019-04-10 17:16:48 +02:00
|
|
|
"strconv"
|
2012-04-30 15:31:14 +10:00
|
|
|
"syscall"
|
|
|
|
|
"testing"
|
|
|
|
|
"time"
|
|
|
|
|
)
|
|
|
|
|
|
2014-02-24 20:35:01 +09:00
|
|
|
// Tests that below functions, structures and constants are consistent
|
|
|
|
|
// on all Unix-like systems.
|
2014-02-24 14:41:10 +09:00
|
|
|
func _() {
|
2014-02-24 20:35:01 +09:00
|
|
|
// program scheduling priority functions and constants
|
2014-02-24 14:41:10 +09:00
|
|
|
var (
|
|
|
|
|
_ func(int, int, int) error = syscall.Setpriority
|
|
|
|
|
_ func(int, int) (int, error) = syscall.Getpriority
|
|
|
|
|
)
|
|
|
|
|
const (
|
|
|
|
|
_ int = syscall.PRIO_USER
|
|
|
|
|
_ int = syscall.PRIO_PROCESS
|
|
|
|
|
_ int = syscall.PRIO_PGRP
|
|
|
|
|
)
|
|
|
|
|
|
2014-02-24 20:35:01 +09:00
|
|
|
// termios constants
|
2014-02-24 14:41:10 +09:00
|
|
|
const (
|
|
|
|
|
_ int = syscall.TCIFLUSH
|
|
|
|
|
_ int = syscall.TCIOFLUSH
|
|
|
|
|
_ int = syscall.TCOFLUSH
|
|
|
|
|
)
|
2014-02-24 20:35:01 +09:00
|
|
|
|
|
|
|
|
// fcntl file locking structure and constants
|
|
|
|
|
var (
|
|
|
|
|
_ = syscall.Flock_t{
|
|
|
|
|
Type: int16(0),
|
|
|
|
|
Whence: int16(0),
|
|
|
|
|
Start: int64(0),
|
|
|
|
|
Len: int64(0),
|
|
|
|
|
Pid: int32(0),
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
const (
|
|
|
|
|
_ = syscall.F_GETLK
|
|
|
|
|
_ = syscall.F_SETLK
|
|
|
|
|
_ = syscall.F_SETLKW
|
|
|
|
|
)
|
2014-02-24 14:41:10 +09:00
|
|
|
}
|
|
|
|
|
|
2014-02-24 20:35:01 +09:00
|
|
|
// TestFcntlFlock tests whether the file locking structure matches
|
|
|
|
|
// the calling convention of each kernel.
|
2015-05-12 01:13:09 -04:00
|
|
|
// On some Linux systems, glibc uses another set of values for the
|
|
|
|
|
// commands and translates them to the correct value that the kernel
|
|
|
|
|
// expects just before the actual fcntl syscall. As Go uses raw
|
|
|
|
|
// syscalls directly, it must use the real value, not the glibc value.
|
|
|
|
|
// Thus this test also verifies that the Flock_t structure can be
|
|
|
|
|
// roundtripped with F_SETLK and F_GETLK.
|
2014-02-24 20:35:01 +09:00
|
|
|
func TestFcntlFlock(t *testing.T) {
|
2020-09-17 15:02:26 -04:00
|
|
|
if runtime.GOOS == "ios" {
|
2015-05-15 08:45:16 -07:00
|
|
|
t.Skip("skipping; no child processes allowed on iOS")
|
|
|
|
|
}
|
2014-02-24 20:35:01 +09:00
|
|
|
flock := syscall.Flock_t{
|
2015-05-12 01:13:09 -04:00
|
|
|
Type: syscall.F_WRLCK,
|
|
|
|
|
Start: 31415, Len: 271828, Whence: 1,
|
2014-02-24 20:35:01 +09:00
|
|
|
}
|
2015-05-12 01:13:09 -04:00
|
|
|
if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
|
|
|
|
|
// parent
|
2021-04-07 22:32:56 +08:00
|
|
|
tempDir := t.TempDir()
|
2017-04-17 21:32:21 +02:00
|
|
|
name := filepath.Join(tempDir, "TestFcntlFlock")
|
2015-05-12 01:13:09 -04:00
|
|
|
fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Open failed: %v", err)
|
|
|
|
|
}
|
syscall: fix finalizer fd close bugs in TestFcntlFlock and TestPassFD
Currently, the syscall test suite takes very little time to run. It
stands to reason that pretty much every time, zero GCs execute.
With CL 309869, this changes because the minimum heap size is lowered,
triggering two bugs in the test suite.
One bug is in TestFcntlFlock, where a raw FD is wrapped in an os.File
whose last reference is passed into a Cmd. That FD is then closed by a
defer syscall.Close, instead of the os.File's Close, so the finalizer
may fire *after* that FD has already been reused by another test.
The second bug is in the child helper process of TestPassFD, where
there's a small window in which a temp file's FD is encoded for an
out-of-band unix domain socket message to the parent, but not yet sent.
The point of encoding is also the last reference that FD's os.File, so a
finalizer may run at any time. While it's safe for the finalizer to run
after the FD is sent, if it runs before, the send will fail, since unix
domain sockets require that any sent FDs are valid.
Change-Id: I2d1bd7e6db6efcc6763273217fd85cb5b9764274
Reviewed-on: https://go-review.googlesource.com/c/go/+/360575
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2021-11-01 22:35:29 +00:00
|
|
|
// f takes ownership of fd, and will close it.
|
|
|
|
|
//
|
|
|
|
|
// N.B. This defer is also necessary to keep f alive
|
|
|
|
|
// while we use its fd, preventing its finalizer from
|
|
|
|
|
// executing.
|
|
|
|
|
f := os.NewFile(uintptr(fd), name)
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
|
|
|
|
if err := syscall.Ftruncate(int(f.Fd()), 1<<20); err != nil {
|
2015-05-12 01:13:09 -04:00
|
|
|
t.Fatalf("Ftruncate(1<<20) failed: %v", err)
|
|
|
|
|
}
|
syscall: fix finalizer fd close bugs in TestFcntlFlock and TestPassFD
Currently, the syscall test suite takes very little time to run. It
stands to reason that pretty much every time, zero GCs execute.
With CL 309869, this changes because the minimum heap size is lowered,
triggering two bugs in the test suite.
One bug is in TestFcntlFlock, where a raw FD is wrapped in an os.File
whose last reference is passed into a Cmd. That FD is then closed by a
defer syscall.Close, instead of the os.File's Close, so the finalizer
may fire *after* that FD has already been reused by another test.
The second bug is in the child helper process of TestPassFD, where
there's a small window in which a temp file's FD is encoded for an
out-of-band unix domain socket message to the parent, but not yet sent.
The point of encoding is also the last reference that FD's os.File, so a
finalizer may run at any time. While it's safe for the finalizer to run
after the FD is sent, if it runs before, the send will fail, since unix
domain sockets require that any sent FDs are valid.
Change-Id: I2d1bd7e6db6efcc6763273217fd85cb5b9764274
Reviewed-on: https://go-review.googlesource.com/c/go/+/360575
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2021-11-01 22:35:29 +00:00
|
|
|
if err := syscall.FcntlFlock(f.Fd(), syscall.F_SETLK, &flock); err != nil {
|
2015-05-12 01:13:09 -04:00
|
|
|
t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
|
|
|
|
|
}
|
syscall: fix finalizer fd close bugs in TestFcntlFlock and TestPassFD
Currently, the syscall test suite takes very little time to run. It
stands to reason that pretty much every time, zero GCs execute.
With CL 309869, this changes because the minimum heap size is lowered,
triggering two bugs in the test suite.
One bug is in TestFcntlFlock, where a raw FD is wrapped in an os.File
whose last reference is passed into a Cmd. That FD is then closed by a
defer syscall.Close, instead of the os.File's Close, so the finalizer
may fire *after* that FD has already been reused by another test.
The second bug is in the child helper process of TestPassFD, where
there's a small window in which a temp file's FD is encoded for an
out-of-band unix domain socket message to the parent, but not yet sent.
The point of encoding is also the last reference that FD's os.File, so a
finalizer may run at any time. While it's safe for the finalizer to run
after the FD is sent, if it runs before, the send will fail, since unix
domain sockets require that any sent FDs are valid.
Change-Id: I2d1bd7e6db6efcc6763273217fd85cb5b9764274
Reviewed-on: https://go-review.googlesource.com/c/go/+/360575
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2021-11-01 22:35:29 +00:00
|
|
|
|
2025-02-24 09:43:41 +01:00
|
|
|
cmd := exec.Command(testenv.Executable(t), "-test.run=^TestFcntlFlock$")
|
2015-05-12 01:13:09 -04:00
|
|
|
cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
|
syscall: fix finalizer fd close bugs in TestFcntlFlock and TestPassFD
Currently, the syscall test suite takes very little time to run. It
stands to reason that pretty much every time, zero GCs execute.
With CL 309869, this changes because the minimum heap size is lowered,
triggering two bugs in the test suite.
One bug is in TestFcntlFlock, where a raw FD is wrapped in an os.File
whose last reference is passed into a Cmd. That FD is then closed by a
defer syscall.Close, instead of the os.File's Close, so the finalizer
may fire *after* that FD has already been reused by another test.
The second bug is in the child helper process of TestPassFD, where
there's a small window in which a temp file's FD is encoded for an
out-of-band unix domain socket message to the parent, but not yet sent.
The point of encoding is also the last reference that FD's os.File, so a
finalizer may run at any time. While it's safe for the finalizer to run
after the FD is sent, if it runs before, the send will fail, since unix
domain sockets require that any sent FDs are valid.
Change-Id: I2d1bd7e6db6efcc6763273217fd85cb5b9764274
Reviewed-on: https://go-review.googlesource.com/c/go/+/360575
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2021-11-01 22:35:29 +00:00
|
|
|
cmd.ExtraFiles = []*os.File{f}
|
2015-05-12 01:13:09 -04:00
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
if len(out) > 0 || err != nil {
|
|
|
|
|
t.Fatalf("child process: %q, %v", out, err)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// child
|
|
|
|
|
got := flock
|
|
|
|
|
// make sure the child lock is conflicting with the parent lock
|
|
|
|
|
got.Start--
|
|
|
|
|
got.Len++
|
|
|
|
|
if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil {
|
|
|
|
|
t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
flock.Pid = int32(syscall.Getppid())
|
|
|
|
|
// Linux kernel always set Whence to 0
|
|
|
|
|
flock.Whence = 0
|
|
|
|
|
if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence {
|
|
|
|
|
os.Exit(0)
|
|
|
|
|
}
|
|
|
|
|
t.Fatalf("FcntlFlock got %v, want %v", got, flock)
|
2014-02-24 14:41:10 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-04-30 15:31:14 +10:00
|
|
|
// TestPassFD tests passing a file descriptor over a Unix socket.
|
|
|
|
|
//
|
|
|
|
|
// This test involved both a parent and child process. The parent
|
|
|
|
|
// process is invoked as a normal test, with "go test", which then
|
|
|
|
|
// runs the child process by running the current test binary with args
|
|
|
|
|
// "-test.run=^TestPassFD$" and an environment variable used to signal
|
|
|
|
|
// that the test should become the child process instead.
|
|
|
|
|
func TestPassFD(t *testing.T) {
|
2015-06-05 11:01:53 -04:00
|
|
|
testenv.MustHaveExec(t)
|
|
|
|
|
|
2019-04-16 14:19:18 +02:00
|
|
|
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
|
|
|
|
|
passFDChild()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-10 17:16:48 +02:00
|
|
|
if runtime.GOOS == "aix" {
|
|
|
|
|
// Unix network isn't properly working on AIX 7.2 with Technical Level < 2
|
|
|
|
|
out, err := exec.Command("oslevel", "-s").Output()
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Skipf("skipping on AIX because oslevel -s failed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(out) < len("7200-XX-ZZ-YYMM") { // AIX 7.2, Tech Level XX, Service Pack ZZ, date YYMM
|
|
|
|
|
t.Skip("skipping on AIX because oslevel -s hasn't the right length")
|
|
|
|
|
}
|
|
|
|
|
aixVer := string(out[:4])
|
|
|
|
|
tl, err := strconv.Atoi(string(out[5:7]))
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Skipf("skipping on AIX because oslevel -s output cannot be parsed: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if aixVer < "7200" || (aixVer == "7200" && tl < 2) {
|
|
|
|
|
t.Skip("skipped on AIX versions previous to 7.2 TL 2")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-07 22:32:56 +08:00
|
|
|
tempDir := t.TempDir()
|
2012-04-30 15:31:14 +10:00
|
|
|
|
|
|
|
|
fds, err := syscall.Socketpair(syscall.AF_LOCAL, syscall.SOCK_STREAM, 0)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("Socketpair: %v", err)
|
|
|
|
|
}
|
|
|
|
|
writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
|
|
|
|
|
readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
|
|
|
|
|
defer writeFile.Close()
|
|
|
|
|
defer readFile.Close()
|
|
|
|
|
|
2025-02-24 09:43:41 +01:00
|
|
|
cmd := exec.Command(testenv.Executable(t), "-test.run=^TestPassFD$", "--", tempDir)
|
2015-05-12 01:13:09 -04:00
|
|
|
cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
|
2012-04-30 15:31:14 +10:00
|
|
|
cmd.ExtraFiles = []*os.File{writeFile}
|
|
|
|
|
|
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
|
if len(out) > 0 || err != nil {
|
|
|
|
|
t.Fatalf("child process: %q, %v", out, err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
c, err := net.FileConn(readFile)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("FileConn: %v", err)
|
|
|
|
|
}
|
|
|
|
|
defer c.Close()
|
|
|
|
|
|
|
|
|
|
uc, ok := c.(*net.UnixConn)
|
|
|
|
|
if !ok {
|
|
|
|
|
t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
buf := make([]byte, 32) // expect 1 byte
|
|
|
|
|
oob := make([]byte, 32) // expect 24 bytes
|
|
|
|
|
closeUnix := time.AfterFunc(5*time.Second, func() {
|
|
|
|
|
t.Logf("timeout reading from unix socket")
|
|
|
|
|
uc.Close()
|
|
|
|
|
})
|
|
|
|
|
_, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
|
2017-11-29 11:38:03 +01:00
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("ReadMsgUnix: %v", err)
|
|
|
|
|
}
|
2012-04-30 15:31:14 +10:00
|
|
|
closeUnix.Stop()
|
|
|
|
|
|
|
|
|
|
scms, err := syscall.ParseSocketControlMessage(oob[:oobn])
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("ParseSocketControlMessage: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(scms) != 1 {
|
|
|
|
|
t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
|
|
|
|
|
}
|
|
|
|
|
scm := scms[0]
|
|
|
|
|
gotFds, err := syscall.ParseUnixRights(&scm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("syscall.ParseUnixRights: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(gotFds) != 1 {
|
|
|
|
|
t.Fatalf("wanted 1 fd; got %#v", gotFds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
|
|
|
|
|
defer f.Close()
|
|
|
|
|
|
2020-10-16 00:49:02 -04:00
|
|
|
got, err := io.ReadAll(f)
|
2012-04-30 15:31:14 +10:00
|
|
|
want := "Hello from child process!\n"
|
|
|
|
|
if string(got) != want {
|
|
|
|
|
t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// passFDChild is the child process used by TestPassFD.
|
|
|
|
|
func passFDChild() {
|
|
|
|
|
defer os.Exit(0)
|
|
|
|
|
|
|
|
|
|
// Look for our fd. It should be fd 3, but we work around an fd leak
|
2015-07-10 17:17:11 -06:00
|
|
|
// bug here (https://golang.org/issue/2603) to let it be elsewhere.
|
2012-04-30 15:31:14 +10:00
|
|
|
var uc *net.UnixConn
|
|
|
|
|
for fd := uintptr(3); fd <= 10; fd++ {
|
|
|
|
|
f := os.NewFile(fd, "unix-conn")
|
|
|
|
|
var ok bool
|
|
|
|
|
netc, _ := net.FileConn(f)
|
|
|
|
|
uc, ok = netc.(*net.UnixConn)
|
|
|
|
|
if ok {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if uc == nil {
|
|
|
|
|
fmt.Println("failed to find unix fd")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Make a file f to send to our parent process on uc.
|
|
|
|
|
// We make it in tempDir, which our parent will clean up.
|
|
|
|
|
flag.Parse()
|
|
|
|
|
tempDir := flag.Arg(0)
|
2020-10-29 14:17:47 -04:00
|
|
|
f, err := os.CreateTemp(tempDir, "")
|
2012-04-30 15:31:14 +10:00
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("TempFile: %v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
syscall: fix finalizer fd close bugs in TestFcntlFlock and TestPassFD
Currently, the syscall test suite takes very little time to run. It
stands to reason that pretty much every time, zero GCs execute.
With CL 309869, this changes because the minimum heap size is lowered,
triggering two bugs in the test suite.
One bug is in TestFcntlFlock, where a raw FD is wrapped in an os.File
whose last reference is passed into a Cmd. That FD is then closed by a
defer syscall.Close, instead of the os.File's Close, so the finalizer
may fire *after* that FD has already been reused by another test.
The second bug is in the child helper process of TestPassFD, where
there's a small window in which a temp file's FD is encoded for an
out-of-band unix domain socket message to the parent, but not yet sent.
The point of encoding is also the last reference that FD's os.File, so a
finalizer may run at any time. While it's safe for the finalizer to run
after the FD is sent, if it runs before, the send will fail, since unix
domain sockets require that any sent FDs are valid.
Change-Id: I2d1bd7e6db6efcc6763273217fd85cb5b9764274
Reviewed-on: https://go-review.googlesource.com/c/go/+/360575
Trust: Michael Knyszek <mknyszek@google.com>
Run-TryBot: Michael Knyszek <mknyszek@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2021-11-01 22:35:29 +00:00
|
|
|
// N.B. This defer is also necessary to keep f alive
|
|
|
|
|
// while we use its fd, preventing its finalizer from
|
|
|
|
|
// executing.
|
|
|
|
|
defer f.Close()
|
2012-04-30 15:31:14 +10:00
|
|
|
|
|
|
|
|
f.Write([]byte("Hello from child process!\n"))
|
2016-04-05 11:22:53 -07:00
|
|
|
f.Seek(0, io.SeekStart)
|
2012-04-30 15:31:14 +10:00
|
|
|
|
|
|
|
|
rights := syscall.UnixRights(int(f.Fd()))
|
|
|
|
|
dummyByte := []byte("x")
|
|
|
|
|
n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
fmt.Printf("WriteMsgUnix: %v", err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if n != 1 || oobn != len(rights) {
|
|
|
|
|
fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-27 15:19:23 +11:00
|
|
|
|
|
|
|
|
// TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
|
|
|
|
|
// and ParseUnixRights are able to successfully round-trip lists of file descriptors.
|
|
|
|
|
func TestUnixRightsRoundtrip(t *testing.T) {
|
|
|
|
|
testCases := [...][][]int{
|
|
|
|
|
{{42}},
|
|
|
|
|
{{1, 2}},
|
|
|
|
|
{{3, 4, 5}},
|
|
|
|
|
{{}},
|
|
|
|
|
{{1, 2}, {3, 4, 5}, {}, {7}},
|
|
|
|
|
}
|
|
|
|
|
for _, testCase := range testCases {
|
|
|
|
|
b := []byte{}
|
|
|
|
|
var n int
|
|
|
|
|
for _, fds := range testCase {
|
|
|
|
|
// Last assignment to n wins
|
|
|
|
|
n = len(b) + syscall.CmsgLen(4*len(fds))
|
|
|
|
|
b = append(b, syscall.UnixRights(fds...)...)
|
|
|
|
|
}
|
|
|
|
|
// Truncate b
|
|
|
|
|
b = b[:n]
|
|
|
|
|
|
|
|
|
|
scms, err := syscall.ParseSocketControlMessage(b)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("ParseSocketControlMessage: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(scms) != len(testCase) {
|
|
|
|
|
t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
|
|
|
|
|
}
|
|
|
|
|
for i, scm := range scms {
|
|
|
|
|
gotFds, err := syscall.ParseUnixRights(&scm)
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("ParseUnixRights: %v", err)
|
|
|
|
|
}
|
|
|
|
|
wantFds := testCase[i]
|
|
|
|
|
if len(gotFds) != len(wantFds) {
|
|
|
|
|
t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
|
|
|
|
|
}
|
|
|
|
|
for j, fd := range gotFds {
|
|
|
|
|
if fd != wantFds[j] {
|
|
|
|
|
t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-24 14:41:10 +09:00
|
|
|
|
2014-05-16 12:15:32 -04:00
|
|
|
func TestSeekFailure(t *testing.T) {
|
2016-04-05 11:22:53 -07:00
|
|
|
_, err := syscall.Seek(-1, 0, io.SeekStart)
|
2014-05-16 12:15:32 -04:00
|
|
|
if err == nil {
|
|
|
|
|
t.Fatalf("Seek(-1, 0, 0) did not fail")
|
|
|
|
|
}
|
|
|
|
|
str := err.Error() // used to crash on Linux
|
|
|
|
|
t.Logf("Seek: %v", str)
|
|
|
|
|
if str == "" {
|
|
|
|
|
t.Fatalf("Seek(-1, 0, 0) return error with empty message")
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-05 17:10:40 +02:00
|
|
|
|
|
|
|
|
func TestSetsockoptString(t *testing.T) {
|
|
|
|
|
// should not panic on empty string, see issue #31277
|
|
|
|
|
err := syscall.SetsockoptString(-1, 0, 0, "")
|
|
|
|
|
if err == nil {
|
|
|
|
|
t.Fatalf("SetsockoptString: did not fail")
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-10-30 11:30:57 +00:00
|
|
|
|
|
|
|
|
func TestENFILETemporary(t *testing.T) {
|
|
|
|
|
if !syscall.ENFILE.Temporary() {
|
|
|
|
|
t.Error("ENFILE is not treated as a temporary error")
|
|
|
|
|
}
|
|
|
|
|
}
|