github.com/dolotech/hongbao@v0.0.0-20191130105438-fd59d7a5dda5/src/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 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 "testing" 19 "time" 20 21 "golang.org/x/sys/unix" 22 ) 23 24 // Tests that below functions, structures and constants are consistent 25 // on all Unix-like systems. 26 func _() { 27 // program scheduling priority functions and constants 28 var ( 29 _ func(int, int, int) error = unix.Setpriority 30 _ func(int, int) (int, error) = unix.Getpriority 31 ) 32 const ( 33 _ int = unix.PRIO_USER 34 _ int = unix.PRIO_PROCESS 35 _ int = unix.PRIO_PGRP 36 ) 37 38 // termios constants 39 const ( 40 _ int = unix.TCIFLUSH 41 _ int = unix.TCIOFLUSH 42 _ int = unix.TCOFLUSH 43 ) 44 45 // fcntl file locking structure and constants 46 var ( 47 _ = unix.Flock_t{ 48 Type: int16(0), 49 Whence: int16(0), 50 Start: int64(0), 51 Len: int64(0), 52 Pid: int32(0), 53 } 54 ) 55 const ( 56 _ = unix.F_GETLK 57 _ = unix.F_SETLK 58 _ = unix.F_SETLKW 59 ) 60 } 61 62 // TestFcntlFlock tests whether the file locking structure matches 63 // the calling convention of each kernel. 64 func TestFcntlFlock(t *testing.T) { 65 name := filepath.Join(os.TempDir(), "TestFcntlFlock") 66 fd, err := unix.Open(name, unix.O_CREAT|unix.O_RDWR|unix.O_CLOEXEC, 0) 67 if err != nil { 68 t.Fatalf("Open failed: %v", err) 69 } 70 defer unix.Unlink(name) 71 defer unix.Close(fd) 72 flock := unix.Flock_t{ 73 Type: unix.F_RDLCK, 74 Start: 0, Len: 0, Whence: 1, 75 } 76 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil { 77 t.Fatalf("FcntlFlock failed: %v", err) 78 } 79 } 80 81 // TestPassFD tests passing a file descriptor over a Unix socket. 82 // 83 // This test involved both a parent and child process. The parent 84 // process is invoked as a normal test, with "go test", which then 85 // runs the child process by running the current test binary with args 86 // "-test.run=^TestPassFD$" and an environment variable used to signal 87 // that the test should become the child process instead. 88 func TestPassFD(t *testing.T) { 89 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { 90 passFDChild() 91 return 92 } 93 94 tempDir, err := ioutil.TempDir("", "TestPassFD") 95 if err != nil { 96 t.Fatal(err) 97 } 98 defer os.RemoveAll(tempDir) 99 100 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0) 101 if err != nil { 102 t.Fatalf("Socketpair: %v", err) 103 } 104 defer unix.Close(fds[0]) 105 defer unix.Close(fds[1]) 106 writeFile := os.NewFile(uintptr(fds[0]), "child-writes") 107 readFile := os.NewFile(uintptr(fds[1]), "parent-reads") 108 defer writeFile.Close() 109 defer readFile.Close() 110 111 cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) 112 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 113 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" { 114 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp) 115 } 116 cmd.ExtraFiles = []*os.File{writeFile} 117 118 out, err := cmd.CombinedOutput() 119 if len(out) > 0 || err != nil { 120 t.Fatalf("child process: %q, %v", out, err) 121 } 122 123 c, err := net.FileConn(readFile) 124 if err != nil { 125 t.Fatalf("FileConn: %v", err) 126 } 127 defer c.Close() 128 129 uc, ok := c.(*net.UnixConn) 130 if !ok { 131 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c) 132 } 133 134 buf := make([]byte, 32) // expect 1 byte 135 oob := make([]byte, 32) // expect 24 bytes 136 closeUnix := time.AfterFunc(5*time.Second, func() { 137 t.Logf("timeout reading from unix socket") 138 uc.Close() 139 }) 140 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob) 141 closeUnix.Stop() 142 143 scms, err := unix.ParseSocketControlMessage(oob[:oobn]) 144 if err != nil { 145 t.Fatalf("ParseSocketControlMessage: %v", err) 146 } 147 if len(scms) != 1 { 148 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms) 149 } 150 scm := scms[0] 151 gotFds, err := unix.ParseUnixRights(&scm) 152 if err != nil { 153 t.Fatalf("unix.ParseUnixRights: %v", err) 154 } 155 if len(gotFds) != 1 { 156 t.Fatalf("wanted 1 fd; got %#v", gotFds) 157 } 158 159 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") 160 defer f.Close() 161 162 got, err := ioutil.ReadAll(f) 163 want := "Hello from child process!\n" 164 if string(got) != want { 165 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) 166 } 167 } 168 169 // passFDChild is the child process used by TestPassFD. 170 func passFDChild() { 171 defer os.Exit(0) 172 173 // Look for our fd. It should be fd 3, but we work around an fd leak 174 // bug here (http://golang.org/issue/2603) to let it be elsewhere. 175 var uc *net.UnixConn 176 for fd := uintptr(3); fd <= 10; fd++ { 177 f := os.NewFile(fd, "unix-conn") 178 var ok bool 179 netc, _ := net.FileConn(f) 180 uc, ok = netc.(*net.UnixConn) 181 if ok { 182 break 183 } 184 } 185 if uc == nil { 186 fmt.Println("failed to find unix fd") 187 return 188 } 189 190 // Make a file f to send to our parent process on uc. 191 // We make it in tempDir, which our parent will clean up. 192 flag.Parse() 193 tempDir := flag.Arg(0) 194 f, err := ioutil.TempFile(tempDir, "") 195 if err != nil { 196 fmt.Printf("TempFile: %v", err) 197 return 198 } 199 200 f.Write([]byte("Hello from child process!\n")) 201 f.Seek(0, 0) 202 203 rights := unix.UnixRights(int(f.Fd())) 204 dummyByte := []byte("x") 205 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil) 206 if err != nil { 207 fmt.Printf("WriteMsgUnix: %v", err) 208 return 209 } 210 if n != 1 || oobn != len(rights) { 211 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights)) 212 return 213 } 214 } 215 216 // TestUnixRightsRoundtrip tests that UnixRights, ParseSocketControlMessage, 217 // and ParseUnixRights are able to successfully round-trip lists of file descriptors. 218 func TestUnixRightsRoundtrip(t *testing.T) { 219 testCases := [...][][]int{ 220 {{42}}, 221 {{1, 2}}, 222 {{3, 4, 5}}, 223 {{}}, 224 {{1, 2}, {3, 4, 5}, {}, {7}}, 225 } 226 for _, testCase := range testCases { 227 b := []byte{} 228 var n int 229 for _, fds := range testCase { 230 // Last assignment to n wins 231 n = len(b) + unix.CmsgLen(4*len(fds)) 232 b = append(b, unix.UnixRights(fds...)...) 233 } 234 // Truncate b 235 b = b[:n] 236 237 scms, err := unix.ParseSocketControlMessage(b) 238 if err != nil { 239 t.Fatalf("ParseSocketControlMessage: %v", err) 240 } 241 if len(scms) != len(testCase) { 242 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms) 243 } 244 for i, scm := range scms { 245 gotFds, err := unix.ParseUnixRights(&scm) 246 if err != nil { 247 t.Fatalf("ParseUnixRights: %v", err) 248 } 249 wantFds := testCase[i] 250 if len(gotFds) != len(wantFds) { 251 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds) 252 } 253 for j, fd := range gotFds { 254 if fd != wantFds[j] { 255 t.Fatalf("expected fd %v, got %v", wantFds[j], fd) 256 } 257 } 258 } 259 } 260 } 261 262 func TestRlimit(t *testing.T) { 263 var rlimit, zero unix.Rlimit 264 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit) 265 if err != nil { 266 t.Fatalf("Getrlimit: save failed: %v", err) 267 } 268 if zero == rlimit { 269 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit) 270 } 271 set := rlimit 272 set.Cur = set.Max - 1 273 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set) 274 if err != nil { 275 t.Fatalf("Setrlimit: set failed: %#v %v", set, err) 276 } 277 var get unix.Rlimit 278 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get) 279 if err != nil { 280 t.Fatalf("Getrlimit: get failed: %v", err) 281 } 282 set = rlimit 283 set.Cur = set.Max - 1 284 if set != get { 285 // Seems like Darwin requires some privilege to 286 // increase the soft limit of rlimit sandbox, though 287 // Setrlimit never reports an error. 288 switch runtime.GOOS { 289 case "darwin": 290 default: 291 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get) 292 } 293 } 294 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit) 295 if err != nil { 296 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err) 297 } 298 } 299 300 func TestSeekFailure(t *testing.T) { 301 _, err := unix.Seek(-1, 0, 0) 302 if err == nil { 303 t.Fatalf("Seek(-1, 0, 0) did not fail") 304 } 305 str := err.Error() // used to crash on Linux 306 t.Logf("Seek: %v", str) 307 if str == "" { 308 t.Fatalf("Seek(-1, 0, 0) return error with empty message") 309 } 310 } 311 312 func TestDup(t *testing.T) { 313 file, err := ioutil.TempFile("", "TestDup") 314 if err != nil { 315 t.Fatalf("Tempfile failed: %v", err) 316 } 317 defer os.Remove(file.Name()) 318 defer file.Close() 319 f := int(file.Fd()) 320 321 newFd, err := unix.Dup(f) 322 if err != nil { 323 t.Fatalf("Dup: %v", err) 324 } 325 326 err = unix.Dup2(newFd, newFd+1) 327 if err != nil { 328 t.Fatalf("Dup2: %v", err) 329 } 330 331 b1 := []byte("Test123") 332 b2 := make([]byte, 7) 333 _, err = unix.Write(newFd+1, b1) 334 if err != nil { 335 t.Fatalf("Write to dup2 fd failed: %v", err) 336 } 337 _, err = unix.Seek(f, 0, 0) 338 _, err = unix.Read(f, b2) 339 if err != nil { 340 t.Fatalf("Read back failed: %v", err) 341 } 342 if string(b1) != string(b2) { 343 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2)) 344 } 345 }