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
25 // Tests that below functions, structures and constants are consistent
26 // on all Unix-like systems.
28 // program scheduling priority functions and constants
30 _
func(int, int, int) error
= syscall
.Setpriority
31 _
func(int, int) (int, error
) = syscall
.Getpriority
34 _
int = syscall
.PRIO_USER
35 _
int = syscall
.PRIO_PROCESS
36 _
int = syscall
.PRIO_PGRP
41 _
int = syscall
.TCIFLUSH
42 _
int = syscall
.TCIOFLUSH
43 _
int = syscall
.TCOFLUSH
46 // fcntl file locking structure and constants
63 // TestFcntlFlock tests whether the file locking structure matches
64 // the calling convention of each kernel.
65 // On some Linux systems, glibc uses another set of values for the
66 // commands and translates them to the correct value that the kernel
67 // expects just before the actual fcntl syscall. As Go uses raw
68 // syscalls directly, it must use the real value, not the glibc value.
69 // Thus this test also verifies that the Flock_t structure can be
70 // roundtripped with F_SETLK and F_GETLK.
71 func TestFcntlFlock(t
*testing
.T
) {
72 if runtime
.GOOS
== "darwin" && (runtime
.GOARCH
== "arm" || runtime
.GOARCH
== "arm64") {
73 t
.Skip("skipping; no child processes allowed on iOS")
75 flock
:= syscall
.Flock_t
{
76 Type
: syscall
.F_WRLCK
,
77 Start
: 31415, Len
: 271828, Whence
: 1,
79 if os
.Getenv("GO_WANT_HELPER_PROCESS") == "" {
81 name
:= filepath
.Join(os
.TempDir(), "TestFcntlFlock")
82 fd
, err
:= syscall
.Open(name
, syscall
.O_CREAT|syscall
.O_RDWR|syscall
.O_CLOEXEC
, 0)
84 t
.Fatalf("Open failed: %v", err
)
86 defer syscall
.Unlink(name
)
87 defer syscall
.Close(fd
)
88 if err
:= syscall
.Ftruncate(fd
, 1<<20); err
!= nil {
89 t
.Fatalf("Ftruncate(1<<20) failed: %v", err
)
91 if err
:= syscall
.FcntlFlock(uintptr(fd
), syscall
.F_SETLK
, &flock
); err
!= nil {
92 t
.Fatalf("FcntlFlock(F_SETLK) failed: %v", err
)
94 cmd
:= exec
.Command(os
.Args
[0], "-test.run=^TestFcntlFlock$")
95 cmd
.Env
= append(os
.Environ(), "GO_WANT_HELPER_PROCESS=1")
96 cmd
.ExtraFiles
= []*os
.File
{os
.NewFile(uintptr(fd
), name
)}
97 out
, err
:= cmd
.CombinedOutput()
98 if len(out
) > 0 || err
!= nil {
99 t
.Fatalf("child process: %q, %v", out
, err
)
104 // make sure the child lock is conflicting with the parent lock
107 if err
:= syscall
.FcntlFlock(3, syscall
.F_GETLK
, &got
); err
!= nil {
108 t
.Fatalf("FcntlFlock(F_GETLK) failed: %v", err
)
110 flock
.Pid
= int32(syscall
.Getppid())
111 // Linux kernel always set Whence to 0
113 if got
.Type
== flock
.Type
&& got
.Start
== flock
.Start
&& got
.Len
== flock
.Len
&& got
.Pid
== flock
.Pid
&& got
.Whence
== flock
.Whence
{
116 t
.Fatalf("FcntlFlock got %v, want %v", got
, flock
)
120 // TestPassFD tests passing a file descriptor over a Unix socket.
122 // This test involved both a parent and child process. The parent
123 // process is invoked as a normal test, with "go test", which then
124 // runs the child process by running the current test binary with args
125 // "-test.run=^TestPassFD$" and an environment variable used to signal
126 // that the test should become the child process instead.
127 func TestPassFD(t
*testing
.T
) {
128 switch runtime
.GOOS
{
130 // TODO(jsing): Figure out why sendmsg is returning EINVAL.
131 t
.Skip("skipping test on dragonfly")
133 // TODO(aram): Figure out why ReadMsgUnix is returning empty message.
134 t
.Skip("skipping test on solaris, see issue 7402")
137 testenv
.MustHaveExec(t
)
139 if os
.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
144 tempDir
, err
:= ioutil
.TempDir("", "TestPassFD")
148 defer os
.RemoveAll(tempDir
)
150 fds
, err
:= syscall
.Socketpair(syscall
.AF_LOCAL
, syscall
.SOCK_STREAM
, 0)
152 t
.Fatalf("Socketpair: %v", err
)
154 defer syscall
.Close(fds
[0])
155 defer syscall
.Close(fds
[1])
156 writeFile
:= os
.NewFile(uintptr(fds
[0]), "child-writes")
157 readFile
:= os
.NewFile(uintptr(fds
[1]), "parent-reads")
158 defer writeFile
.Close()
159 defer readFile
.Close()
161 cmd
:= exec
.Command(os
.Args
[0], "-test.run=^TestPassFD$", "--", tempDir
)
162 cmd
.Env
= append(os
.Environ(), "GO_WANT_HELPER_PROCESS=1")
163 cmd
.ExtraFiles
= []*os
.File
{writeFile
}
165 out
, err
:= cmd
.CombinedOutput()
166 if len(out
) > 0 || err
!= nil {
167 t
.Fatalf("child process: %q, %v", out
, err
)
170 c
, err
:= net
.FileConn(readFile
)
172 t
.Fatalf("FileConn: %v", err
)
176 uc
, ok
:= c
.(*net
.UnixConn
)
178 t
.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c
)
181 buf
:= make([]byte, 32) // expect 1 byte
182 oob
:= make([]byte, 32) // expect 24 bytes
183 closeUnix
:= time
.AfterFunc(5*time
.Second
, func() {
184 t
.Logf("timeout reading from unix socket")
187 _
, oobn
, _
, _
, err
:= uc
.ReadMsgUnix(buf
, oob
)
190 scms
, err
:= syscall
.ParseSocketControlMessage(oob
[:oobn
])
192 t
.Fatalf("ParseSocketControlMessage: %v", err
)
195 t
.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms
)
198 gotFds
, err
:= syscall
.ParseUnixRights(&scm
)
200 t
.Fatalf("syscall.ParseUnixRights: %v", err
)
202 if len(gotFds
) != 1 {
203 t
.Fatalf("wanted 1 fd; got %#v", gotFds
)
206 f
:= os
.NewFile(uintptr(gotFds
[0]), "fd-from-child")
209 got
, err
:= ioutil
.ReadAll(f
)
210 want
:= "Hello from child process!\n"
211 if string(got
) != want
{
212 t
.Errorf("child process ReadAll: %q, %v; want %q", got
, err
, want
)
216 // passFDChild is the child process used by TestPassFD.
220 // Look for our fd. It should be fd 3, but we work around an fd leak
221 // bug here (https://golang.org/issue/2603) to let it be elsewhere.
223 for fd
:= uintptr(3); fd
<= 10; fd
++ {
224 f
:= os
.NewFile(fd
, "unix-conn")
226 netc
, _
:= net
.FileConn(f
)
227 uc
, ok
= netc
.(*net
.UnixConn
)
233 fmt
.Println("failed to find unix fd")
237 // Make a file f to send to our parent process on uc.
238 // We make it in tempDir, which our parent will clean up.
240 tempDir
:= flag
.Arg(0)
241 f
, err
:= ioutil
.TempFile(tempDir
, "")
243 fmt
.Printf("TempFile: %v", err
)
247 f
.Write([]byte("Hello from child process!\n"))
248 f
.Seek(0, io
.SeekStart
)
250 rights
:= syscall
.UnixRights(int(f
.Fd()))
251 dummyByte
:= []byte("x")
252 n
, oobn
, err
:= uc
.WriteMsgUnix(dummyByte
, rights
, nil)
254 fmt
.Printf("WriteMsgUnix: %v", err
)
257 if n
!= 1 || oobn
!= len(rights
) {
258 fmt
.Printf("WriteMsgUnix = %d, %d; want 1, %d", n
, oobn
, len(rights
))
263 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage,
264 // and ParseUnixRights are able to successfully round-trip lists of file descriptors.
265 func TestUnixRightsRoundtrip(t
*testing
.T
) {
266 testCases
:= [...][][]int{
271 {{1, 2}, {3, 4, 5}, {}, {7}},
273 for _
, testCase
:= range testCases
{
276 for _
, fds
:= range testCase
{
277 // Last assignment to n wins
278 n
= len(b
) + syscall
.CmsgLen(4*len(fds
))
279 b
= append(b
, syscall
.UnixRights(fds
...)...)
284 scms
, err
:= syscall
.ParseSocketControlMessage(b
)
286 t
.Fatalf("ParseSocketControlMessage: %v", err
)
288 if len(scms
) != len(testCase
) {
289 t
.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase
), scms
)
291 for i
, scm
:= range scms
{
292 gotFds
, err
:= syscall
.ParseUnixRights(&scm
)
294 t
.Fatalf("ParseUnixRights: %v", err
)
296 wantFds
:= testCase
[i
]
297 if len(gotFds
) != len(wantFds
) {
298 t
.Fatalf("expected %v fds, got %#v", len(wantFds
), gotFds
)
300 for j
, fd
:= range gotFds
{
301 if fd
!= wantFds
[j
] {
302 t
.Fatalf("expected fd %v, got %v", wantFds
[j
], fd
)
309 func TestRlimit(t
*testing
.T
) {
310 var rlimit
, zero syscall
.Rlimit
311 err
:= syscall
.Getrlimit(syscall
.RLIMIT_NOFILE
, &rlimit
)
313 t
.Fatalf("Getrlimit: save failed: %v", err
)
316 t
.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit
)
319 set
.Cur
= set
.Max
- 1
320 err
= syscall
.Setrlimit(syscall
.RLIMIT_NOFILE
, &set
)
322 t
.Fatalf("Setrlimit: set failed: %#v %v", set
, err
)
324 var get syscall
.Rlimit
325 err
= syscall
.Getrlimit(syscall
.RLIMIT_NOFILE
, &get
)
327 t
.Fatalf("Getrlimit: get failed: %v", err
)
330 set
.Cur
= set
.Max
- 1
332 // Seems like Darwin requires some privilege to
333 // increase the soft limit of rlimit sandbox, though
334 // Setrlimit never reports an error.
335 switch runtime
.GOOS
{
338 t
.Fatalf("Rlimit: change failed: wanted %#v got %#v", set
, get
)
341 err
= syscall
.Setrlimit(syscall
.RLIMIT_NOFILE
, &rlimit
)
343 t
.Fatalf("Setrlimit: restore failed: %#v %v", rlimit
, err
)
347 func TestSeekFailure(t
*testing
.T
) {
348 _
, err
:= syscall
.Seek(-1, 0, io
.SeekStart
)
350 t
.Fatalf("Seek(-1, 0, 0) did not fail")
352 str
:= err
.Error() // used to crash on Linux
353 t
.Logf("Seek: %v", str
)
355 t
.Fatalf("Seek(-1, 0, 0) return error with empty message")