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.
5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
24 // Tests that below functions, structures and constants are consistent
25 // on all Unix-like systems.
27 // program scheduling priority functions and constants
29 _
func(int, int, int) error
= syscall
.Setpriority
30 _
func(int, int) (int, error
) = syscall
.Getpriority
33 _
int = syscall
.PRIO_USER
34 _
int = syscall
.PRIO_PROCESS
35 _
int = syscall
.PRIO_PGRP
40 _
int = syscall
.TCIFLUSH
41 _
int = syscall
.TCIOFLUSH
42 _
int = syscall
.TCOFLUSH
45 // fcntl file locking structure and constants
62 // TestFcntlFlock tests whether the file locking structure matches
63 // the calling convention of each kernel.
64 // On some Linux systems, glibc uses another set of values for the
65 // commands and translates them to the correct value that the kernel
66 // expects just before the actual fcntl syscall. As Go uses raw
67 // syscalls directly, it must use the real value, not the glibc value.
68 // Thus this test also verifies that the Flock_t structure can be
69 // roundtripped with F_SETLK and F_GETLK.
70 func TestFcntlFlock(t
*testing
.T
) {
71 if runtime
.GOOS
== "darwin" && (runtime
.GOARCH
== "arm" || runtime
.GOARCH
== "arm64") {
72 t
.Skip("skipping; no child processes allowed on iOS")
74 flock
:= syscall
.Flock_t
{
75 Type
: syscall
.F_WRLCK
,
76 Start
: 31415, Len
: 271828, Whence
: 1,
78 if os
.Getenv("GO_WANT_HELPER_PROCESS") == "" {
80 name
:= filepath
.Join(os
.TempDir(), "TestFcntlFlock")
81 fd
, err
:= syscall
.Open(name
, syscall
.O_CREAT|syscall
.O_RDWR|syscall
.O_CLOEXEC
, 0)
83 t
.Fatalf("Open failed: %v", err
)
85 defer syscall
.Unlink(name
)
86 defer syscall
.Close(fd
)
87 if err
:= syscall
.Ftruncate(fd
, 1<<20); err
!= nil {
88 t
.Fatalf("Ftruncate(1<<20) failed: %v", err
)
90 if err
:= syscall
.FcntlFlock(uintptr(fd
), syscall
.F_SETLK
, &flock
); err
!= nil {
91 t
.Fatalf("FcntlFlock(F_SETLK) failed: %v", err
)
93 cmd
:= exec
.Command(os
.Args
[0], "-test.run=^TestFcntlFlock$")
94 cmd
.Env
= append(os
.Environ(), "GO_WANT_HELPER_PROCESS=1")
95 cmd
.ExtraFiles
= []*os
.File
{os
.NewFile(uintptr(fd
), name
)}
96 out
, err
:= cmd
.CombinedOutput()
97 if len(out
) > 0 || err
!= nil {
98 t
.Fatalf("child process: %q, %v", out
, err
)
103 // make sure the child lock is conflicting with the parent lock
106 if err
:= syscall
.FcntlFlock(3, syscall
.F_GETLK
, &got
); err
!= nil {
107 t
.Fatalf("FcntlFlock(F_GETLK) failed: %v", err
)
109 flock
.Pid
= int32(syscall
.Getppid())
110 // Linux kernel always set Whence to 0
112 if got
.Type
== flock
.Type
&& got
.Start
== flock
.Start
&& got
.Len
== flock
.Len
&& got
.Pid
== flock
.Pid
&& got
.Whence
== flock
.Whence
{
115 t
.Fatalf("FcntlFlock got %v, want %v", got
, flock
)
119 // TestPassFD tests passing a file descriptor over a Unix socket.
121 // This test involved both a parent and child process. The parent
122 // process is invoked as a normal test, with "go test", which then
123 // runs the child process by running the current test binary with args
124 // "-test.run=^TestPassFD$" and an environment variable used to signal
125 // that the test should become the child process instead.
126 func TestPassFD(t
*testing
.T
) {
127 switch runtime
.GOOS
{
129 // TODO(jsing): Figure out why sendmsg is returning EINVAL.
130 t
.Skip("skipping test on dragonfly")
132 // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
133 t
.Skip("skipping test on solaris, see issue 7402")
136 testenv
.MustHaveExec(t
)
138 if os
.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
143 tempDir
, err
:= ioutil
.TempDir("", "TestPassFD")
147 defer os
.RemoveAll(tempDir
)
149 fds
, err
:= syscall
.Socketpair(syscall
.AF_LOCAL
, syscall
.SOCK_STREAM
, 0)
151 t
.Fatalf("Socketpair: %v", err
)
153 defer syscall
.Close(fds
[0])
154 defer syscall
.Close(fds
[1])
155 writeFile
:= os
.NewFile(uintptr(fds
[0]), "child-writes")
156 readFile
:= os
.NewFile(uintptr(fds
[1]), "parent-reads")
157 defer writeFile
.Close()
158 defer readFile
.Close()
160 cmd
:= exec
.Command(os
.Args
[0], "-test.run=^TestPassFD$", "--", tempDir
)
161 cmd
.Env
= append(os
.Environ(), "GO_WANT_HELPER_PROCESS=1")
162 cmd
.ExtraFiles
= []*os
.File
{writeFile
}
164 out
, err
:= cmd
.CombinedOutput()
165 if len(out
) > 0 || err
!= nil {
166 t
.Fatalf("child process: %q, %v", out
, err
)
169 c
, err
:= net
.FileConn(readFile
)
171 t
.Fatalf("FileConn: %v", err
)
175 uc
, ok
:= c
.(*net
.UnixConn
)
177 t
.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c
)
180 buf
:= make([]byte, 32) // expect 1 byte
181 oob
:= make([]byte, 32) // expect 24 bytes
182 closeUnix
:= time
.AfterFunc(5*time
.Second
, func() {
183 t
.Logf("timeout reading from unix socket")
186 _
, oobn
, _
, _
, err
:= uc
.ReadMsgUnix(buf
, oob
)
189 scms
, err
:= syscall
.ParseSocketControlMessage(oob
[:oobn
])
191 t
.Fatalf("ParseSocketControlMessage: %v", err
)
194 t
.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms
)
197 gotFds
, err
:= syscall
.ParseUnixRights(&scm
)
199 t
.Fatalf("syscall.ParseUnixRights: %v", err
)
201 if len(gotFds
) != 1 {
202 t
.Fatalf("wanted 1 fd; got %#v", gotFds
)
205 f
:= os
.NewFile(uintptr(gotFds
[0]), "fd-from-child")
208 got
, err
:= ioutil
.ReadAll(f
)
209 want
:= "Hello from child process!\n"
210 if string(got
) != want
{
211 t
.Errorf("child process ReadAll: %q, %v; want %q", got
, err
, want
)
215 // passFDChild is the child process used by TestPassFD.
219 // Look for our fd. It should be fd 3, but we work around an fd leak
220 // bug here (https://golang.org/issue/2603) to let it be elsewhere.
222 for fd
:= uintptr(3); fd
<= 10; fd
++ {
223 f
:= os
.NewFile(fd
, "unix-conn")
225 netc
, _
:= net
.FileConn(f
)
226 uc
, ok
= netc
.(*net
.UnixConn
)
232 fmt
.Println("failed to find unix fd")
236 // Make a file f to send to our parent process on uc.
237 // We make it in tempDir, which our parent will clean up.
239 tempDir
:= flag
.Arg(0)
240 f
, err
:= ioutil
.TempFile(tempDir
, "")
242 fmt
.Printf("TempFile: %v", err
)
246 f
.Write([]byte("Hello from child process!\n"))
249 rights
:= syscall
.UnixRights(int(f
.Fd()))
250 dummyByte
:= []byte("x")
251 n
, oobn
, err
:= uc
.WriteMsgUnix(dummyByte
, rights
, nil)
253 fmt
.Printf("WriteMsgUnix: %v", err
)
256 if n
!= 1 || oobn
!= len(rights
) {
257 fmt
.Printf("WriteMsgUnix = %d, %d; want 1, %d", n
, oobn
, len(rights
))
262 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
263 // and ParseUnixRights are able to successfully round-trip lists of file descriptors.
264 func TestUnixRightsRoundtrip(t
*testing
.T
) {
265 testCases
:= [...][][]int{
270 {{1, 2}, {3, 4, 5}, {}, {7}},
272 for _
, testCase
:= range testCases
{
275 for _
, fds
:= range testCase
{
276 // Last assignment to n wins
277 n
= len(b
) + syscall
.CmsgLen(4*len(fds
))
278 b
= append(b
, syscall
.UnixRights(fds
...)...)
283 scms
, err
:= syscall
.ParseSocketControlMessage(b
)
285 t
.Fatalf("ParseSocketControlMessage: %v", err
)
287 if len(scms
) != len(testCase
) {
288 t
.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase
), scms
)
290 for i
, scm
:= range scms
{
291 gotFds
, err
:= syscall
.ParseUnixRights(&scm
)
293 t
.Fatalf("ParseUnixRights: %v", err
)
295 wantFds
:= testCase
[i
]
296 if len(gotFds
) != len(wantFds
) {
297 t
.Fatalf("expected %v fds, got %#v", len(wantFds
), gotFds
)
299 for j
, fd
:= range gotFds
{
300 if fd
!= wantFds
[j
] {
301 t
.Fatalf("expected fd %v, got %v", wantFds
[j
], fd
)
308 func TestRlimit(t
*testing
.T
) {
309 var rlimit
, zero syscall
.Rlimit
310 err
:= syscall
.Getrlimit(syscall
.RLIMIT_NOFILE
, &rlimit
)
312 t
.Fatalf("Getrlimit: save failed: %v", err
)
315 t
.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit
)
318 set
.Cur
= set
.Max
- 1
319 err
= syscall
.Setrlimit(syscall
.RLIMIT_NOFILE
, &set
)
321 t
.Fatalf("Setrlimit: set failed: %#v %v", set
, err
)
323 var get syscall
.Rlimit
324 err
= syscall
.Getrlimit(syscall
.RLIMIT_NOFILE
, &get
)
326 t
.Fatalf("Getrlimit: get failed: %v", err
)
329 set
.Cur
= set
.Max
- 1
331 // Seems like Darwin requires some privilege to
332 // increase the soft limit of rlimit sandbox, though
333 // Setrlimit never reports an error.
334 switch runtime
.GOOS
{
337 t
.Fatalf("Rlimit: change failed: wanted %#v got %#v", set
, get
)
340 err
= syscall
.Setrlimit(syscall
.RLIMIT_NOFILE
, &rlimit
)
342 t
.Fatalf("Setrlimit: restore failed: %#v %v", rlimit
, err
)
346 func TestSeekFailure(t
*testing
.T
) {
347 _
, err
:= syscall
.Seek(-1, 0, 0)
349 t
.Fatalf("Seek(-1, 0, 0) did not fail")
351 str
:= err
.Error() // used to crash on Linux
352 t
.Logf("Seek: %v", str
)
354 t
.Fatalf("Seek(-1, 0, 0) return error with empty message")