1
2
3
4
5
6
7 package unix_test
8
9 import (
10 "bytes"
11 "flag"
12 "fmt"
13 "io"
14 "net"
15 "os"
16 "os/exec"
17 "path/filepath"
18 "reflect"
19 "runtime"
20 "strconv"
21 "sync"
22 "syscall"
23 "testing"
24 "time"
25
26 "golang.org/x/sys/unix"
27 )
28
29
30
31 func _() {
32
33 var (
34 _ func(int, int, int) error = unix.Setpriority
35 _ func(int, int) (int, error) = unix.Getpriority
36 )
37 const (
38 _ int = unix.PRIO_USER
39 _ int = unix.PRIO_PROCESS
40 _ int = unix.PRIO_PGRP
41 )
42
43
44 const (
45 _ int = unix.TCIFLUSH
46 _ int = unix.TCIOFLUSH
47 _ int = unix.TCOFLUSH
48 )
49
50
51 var (
52 _ = unix.Flock_t{
53 Type: int16(0),
54 Whence: int16(0),
55 Start: int64(0),
56 Len: int64(0),
57 Pid: int32(0),
58 }
59 )
60 const (
61 _ = unix.F_GETLK
62 _ = unix.F_SETLK
63 _ = unix.F_SETLKW
64 )
65 }
66
67 func TestErrnoSignalName(t *testing.T) {
68 testErrors := []struct {
69 num syscall.Errno
70 name string
71 }{
72 {syscall.EPERM, "EPERM"},
73 {syscall.EINVAL, "EINVAL"},
74 {syscall.ENOENT, "ENOENT"},
75 }
76
77 for _, te := range testErrors {
78 t.Run(fmt.Sprintf("%d/%s", te.num, te.name), func(t *testing.T) {
79 e := unix.ErrnoName(te.num)
80 if e != te.name {
81 t.Errorf("ErrnoName(%d) returned %s, want %s", te.num, e, te.name)
82 }
83 })
84 }
85
86 testSignals := []struct {
87 num syscall.Signal
88 name string
89 }{
90 {syscall.SIGHUP, "SIGHUP"},
91 {syscall.SIGPIPE, "SIGPIPE"},
92 {syscall.SIGSEGV, "SIGSEGV"},
93 }
94
95 for _, ts := range testSignals {
96 t.Run(fmt.Sprintf("%d/%s", ts.num, ts.name), func(t *testing.T) {
97 s := unix.SignalName(ts.num)
98 if s != ts.name {
99 t.Errorf("SignalName(%d) returned %s, want %s", ts.num, s, ts.name)
100 }
101 })
102 }
103 }
104
105 func TestSignalNum(t *testing.T) {
106 testSignals := []struct {
107 name string
108 want syscall.Signal
109 }{
110 {"SIGHUP", syscall.SIGHUP},
111 {"SIGPIPE", syscall.SIGPIPE},
112 {"SIGSEGV", syscall.SIGSEGV},
113 {"NONEXISTS", 0},
114 }
115 for _, ts := range testSignals {
116 t.Run(fmt.Sprintf("%s/%d", ts.name, ts.want), func(t *testing.T) {
117 got := unix.SignalNum(ts.name)
118 if got != ts.want {
119 t.Errorf("SignalNum(%s) returned %d, want %d", ts.name, got, ts.want)
120 }
121 })
122
123 }
124 }
125
126 func TestFcntlInt(t *testing.T) {
127 t.Parallel()
128 file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
129 if err != nil {
130 t.Fatal(err)
131 }
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
144
145 func TestFcntlFlock(t *testing.T) {
146 name := filepath.Join(t.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.Close(fd)
152 flock := unix.Flock_t{
153 Type: unix.F_RDLCK,
154 Start: 0, Len: 0, Whence: 1,
155 }
156 if err := unix.FcntlFlock(uintptr(fd), unix.F_GETLK, &flock); err != nil {
157 t.Fatalf("FcntlFlock failed: %v", err)
158 }
159 }
160
161
162
163
164
165
166
167
168 func TestPassFD(t *testing.T) {
169 if runtime.GOOS == "ios" {
170 t.Skip("cannot exec subprocess on iOS, skipping test")
171 }
172
173 if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
174 passFDChild()
175 return
176 }
177
178 if runtime.GOOS == "aix" {
179
180
181 out, err := exec.Command("oslevel", "-s").Output()
182 if err != nil {
183 t.Skipf("skipping on AIX because oslevel -s failed: %v", err)
184 }
185
186 if len(out) < len("7200-XX-ZZ-YYMM") {
187 t.Skip("skipping on AIX because oslevel -s hasn't the right length")
188 }
189 aixVer := string(out[:4])
190 tl, err := strconv.Atoi(string(out[5:7]))
191 if err != nil {
192 t.Skipf("skipping on AIX because oslevel -s output cannot be parsed: %v", err)
193 }
194 if aixVer < "7200" || (aixVer == "7200" && tl < 2) {
195 t.Skip("skipped on AIX versions previous to 7.2 TL 2")
196 }
197 }
198
199 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
200 if err != nil {
201 t.Fatalf("Socketpair: %v", err)
202 }
203 writeFile := os.NewFile(uintptr(fds[0]), "child-writes")
204 readFile := os.NewFile(uintptr(fds[1]), "parent-reads")
205 defer writeFile.Close()
206 defer readFile.Close()
207
208 exe, err := os.Executable()
209 if err != nil {
210 t.Fatal(err)
211 }
212 cmd := exec.Command(exe, "-test.run=^TestPassFD$", "--", t.TempDir())
213 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
214 if lp := os.Getenv("LD_LIBRARY_PATH"); lp != "" {
215 cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+lp)
216 }
217 cmd.ExtraFiles = []*os.File{writeFile}
218
219 out, err := cmd.CombinedOutput()
220 if len(out) > 0 || err != nil {
221 t.Fatalf("child process: %q, %v", out, err)
222 }
223
224 c, err := net.FileConn(readFile)
225 if err != nil {
226 t.Fatalf("FileConn: %v", err)
227 }
228 defer c.Close()
229
230 uc, ok := c.(*net.UnixConn)
231 if !ok {
232 t.Fatalf("unexpected FileConn type; expected UnixConn, got %T", c)
233 }
234
235 buf := make([]byte, 32)
236 oob := make([]byte, 32)
237 closeUnix := time.AfterFunc(5*time.Second, func() {
238 t.Logf("timeout reading from unix socket")
239 uc.Close()
240 })
241 _, oobn, _, _, err := uc.ReadMsgUnix(buf, oob)
242 if err != nil {
243 t.Fatalf("ReadMsgUnix: %v", err)
244 }
245 closeUnix.Stop()
246
247 scms, err := unix.ParseSocketControlMessage(oob[:oobn])
248 if err != nil {
249 t.Fatalf("ParseSocketControlMessage: %v", err)
250 }
251 if len(scms) != 1 {
252 t.Fatalf("expected 1 SocketControlMessage; got scms = %#v", scms)
253 }
254 scm := scms[0]
255 gotFds, err := unix.ParseUnixRights(&scm)
256 if err != nil {
257 t.Fatalf("unix.ParseUnixRights: %v", err)
258 }
259 if len(gotFds) != 1 {
260 t.Fatalf("wanted 1 fd; got %#v", gotFds)
261 }
262
263 f := os.NewFile(uintptr(gotFds[0]), "fd-from-child")
264 defer f.Close()
265
266 got, err := io.ReadAll(f)
267 want := "Hello from child process!\n"
268 if string(got) != want {
269 t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want)
270 }
271 }
272
273
274 func passFDChild() {
275 defer os.Exit(0)
276
277
278
279 var uc *net.UnixConn
280 for fd := uintptr(3); fd <= 10; fd++ {
281 f := os.NewFile(fd, "unix-conn")
282 var ok bool
283 netc, _ := net.FileConn(f)
284 uc, ok = netc.(*net.UnixConn)
285 if ok {
286 break
287 }
288 }
289 if uc == nil {
290 fmt.Println("failed to find unix fd")
291 return
292 }
293
294
295
296 flag.Parse()
297 tempDir := flag.Arg(0)
298 f, err := os.Create(filepath.Join(tempDir, "file"))
299 if err != nil {
300 fmt.Println(err)
301 return
302 }
303
304 f.Write([]byte("Hello from child process!\n"))
305 f.Seek(0, 0)
306
307 rights := unix.UnixRights(int(f.Fd()))
308 dummyByte := []byte("x")
309 n, oobn, err := uc.WriteMsgUnix(dummyByte, rights, nil)
310 if err != nil {
311 fmt.Printf("WriteMsgUnix: %v", err)
312 return
313 }
314 if n != 1 || oobn != len(rights) {
315 fmt.Printf("WriteMsgUnix = %d, %d; want 1, %d", n, oobn, len(rights))
316 return
317 }
318 }
319
320
321
322 func TestUnixRightsRoundtrip(t *testing.T) {
323 testCases := [...][][]int{
324 {{42}},
325 {{1, 2}},
326 {{3, 4, 5}},
327 {{}},
328 {{1, 2}, {3, 4, 5}, {}, {7}},
329 }
330 for _, testCase := range testCases {
331 b := []byte{}
332 var n int
333 for _, fds := range testCase {
334
335 n = len(b) + unix.CmsgLen(4*len(fds))
336 b = append(b, unix.UnixRights(fds...)...)
337 }
338
339 b = b[:n]
340
341 scms, err := unix.ParseSocketControlMessage(b)
342 if err != nil {
343 t.Fatalf("ParseSocketControlMessage: %v", err)
344 }
345 if len(scms) != len(testCase) {
346 t.Fatalf("expected %v SocketControlMessage; got scms = %#v", len(testCase), scms)
347 }
348
349 var c int
350 for len(b) > 0 {
351 hdr, data, remainder, err := unix.ParseOneSocketControlMessage(b)
352 if err != nil {
353 t.Fatalf("ParseOneSocketControlMessage: %v", err)
354 }
355 if scms[c].Header != hdr || !bytes.Equal(scms[c].Data, data) {
356 t.Fatal("expected SocketControlMessage header and data to match")
357 }
358 b = remainder
359 c++
360 }
361 if c != len(scms) {
362 t.Fatalf("expected %d SocketControlMessages; got %d", len(scms), c)
363 }
364
365 for i, scm := range scms {
366 gotFds, err := unix.ParseUnixRights(&scm)
367 if err != nil {
368 t.Fatalf("ParseUnixRights: %v", err)
369 }
370 wantFds := testCase[i]
371 if len(gotFds) != len(wantFds) {
372 t.Fatalf("expected %v fds, got %#v", len(wantFds), gotFds)
373 }
374 for j, fd := range gotFds {
375 if fd != wantFds[j] {
376 t.Fatalf("expected fd %v, got %v", wantFds[j], fd)
377 }
378 }
379 }
380 }
381 }
382
383 func TestRlimit(t *testing.T) {
384 var rlimit, zero unix.Rlimit
385 err := unix.Getrlimit(unix.RLIMIT_NOFILE, &rlimit)
386 if err != nil {
387 t.Fatalf("Getrlimit: save failed: %v", err)
388 }
389 if zero == rlimit {
390 t.Fatalf("Getrlimit: save failed: got zero value %#v", rlimit)
391 }
392 set := rlimit
393 set.Cur = set.Max - 1
394 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 {
395
396
397
398 set.Cur = 4096
399 }
400 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &set)
401 if err != nil {
402 t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
403 }
404 var get unix.Rlimit
405 err = unix.Getrlimit(unix.RLIMIT_NOFILE, &get)
406 if err != nil {
407 t.Fatalf("Getrlimit: get failed: %v", err)
408 }
409 set = rlimit
410 set.Cur = set.Max - 1
411 if (runtime.GOOS == "darwin" || runtime.GOOS == "ios") && set.Cur > 4096 {
412 set.Cur = 4096
413 }
414 if set != get {
415
416
417
418 switch runtime.GOOS {
419 case "darwin", "ios":
420 default:
421 t.Fatalf("Rlimit: change failed: wanted %#v got %#v", set, get)
422 }
423 }
424 err = unix.Setrlimit(unix.RLIMIT_NOFILE, &rlimit)
425 if err != nil {
426 t.Fatalf("Setrlimit: restore failed: %#v %v", rlimit, err)
427 }
428
429
430 _ = unix.Rlimit{
431 Cur: unix.RLIM_INFINITY,
432 Max: unix.RLIM_INFINITY,
433 }
434 }
435
436 func TestSeekFailure(t *testing.T) {
437 _, err := unix.Seek(-1, 0, 0)
438 if err == nil {
439 t.Fatalf("Seek(-1, 0, 0) did not fail")
440 }
441 str := err.Error()
442 t.Logf("Seek: %v", str)
443 if str == "" {
444 t.Fatalf("Seek(-1, 0, 0) return error with empty message")
445 }
446 }
447
448 func TestSetsockoptString(t *testing.T) {
449
450 err := unix.SetsockoptString(-1, 0, 0, "")
451 if err == nil {
452 t.Fatalf("SetsockoptString: did not fail")
453 }
454 }
455
456 func TestDup(t *testing.T) {
457 file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
458 if err != nil {
459 t.Fatal(err)
460 }
461 defer file.Close()
462 f := int(file.Fd())
463
464 newFd, err := unix.Dup(f)
465 if err != nil {
466 t.Fatalf("Dup: %v", err)
467 }
468
469
470
471 nullFile, err := os.Open("/dev/null")
472 if err != nil {
473 t.Fatal(err)
474 }
475 dupFd := int(file.Fd())
476 err = unix.Dup2(newFd, dupFd)
477 if err != nil {
478 t.Fatalf("Dup2: %v", err)
479 }
480
481
482 runtime.KeepAlive(nullFile)
483
484 b1 := []byte("Test123")
485 b2 := make([]byte, 7)
486 _, err = unix.Write(dupFd, b1)
487 if err != nil {
488 t.Fatalf("Write to dup2 fd failed: %v", err)
489 }
490 _, err = unix.Seek(f, 0, 0)
491 if err != nil {
492 t.Fatalf("Seek failed: %v", err)
493 }
494 _, err = unix.Read(f, b2)
495 if err != nil {
496 t.Fatalf("Read back failed: %v", err)
497 }
498 if string(b1) != string(b2) {
499 t.Errorf("Dup: stdout write not in file, expected %v, got %v", string(b1), string(b2))
500 }
501 }
502
503 func TestPoll(t *testing.T) {
504 if runtime.GOOS == "android" || runtime.GOOS == "ios" {
505 t.Skip("mkfifo syscall is not available on android and iOS, skipping test")
506 }
507
508 chtmpdir(t)
509 f := mktmpfifo(t)
510
511 const timeout = 100
512
513 ok := make(chan bool, 1)
514 go func() {
515 select {
516 case <-time.After(10 * timeout * time.Millisecond):
517 t.Errorf("Poll: failed to timeout after %d milliseconds", 10*timeout)
518 case <-ok:
519 }
520 }()
521
522 for {
523 fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}}
524 n, err := unix.Poll(fds, timeout)
525 ok <- true
526 if err == unix.EINTR {
527 t.Logf("Poll interrupted")
528 continue
529 } else if err != nil {
530 t.Errorf("Poll: unexpected error: %v", err)
531 return
532 }
533 if n != 0 {
534 t.Errorf("Poll: wrong number of events: got %v, expected %v", n, 0)
535
536
537
538
539 if fds[0].Revents&unix.POLLIN != 0 {
540 t.Log("found POLLIN event")
541 }
542 if fds[0].Revents&unix.POLLPRI != 0 {
543 t.Log("found POLLPRI event")
544 }
545 if fds[0].Revents&unix.POLLOUT != 0 {
546 t.Log("found POLLOUT event")
547 }
548 if fds[0].Revents&unix.POLLERR != 0 {
549 t.Log("found POLLERR event")
550 }
551 if fds[0].Revents&unix.POLLHUP != 0 {
552 t.Log("found POLLHUP event")
553 }
554 if fds[0].Revents&unix.POLLNVAL != 0 {
555 t.Log("found POLLNVAL event")
556 }
557 }
558 break
559 }
560 }
561
562 func TestSelect(t *testing.T) {
563 for {
564 n, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0})
565 if err == unix.EINTR {
566 t.Logf("Select interrupted")
567 continue
568 } else if err != nil {
569 t.Fatalf("Select: %v", err)
570 }
571 if n != 0 {
572 t.Fatalf("Select: got %v ready file descriptors, expected 0", n)
573 }
574 break
575 }
576
577 dur := 250 * time.Millisecond
578 var took time.Duration
579 for {
580
581
582
583 tv := unix.NsecToTimeval(int64(dur))
584 start := time.Now()
585 n, err := unix.Select(0, nil, nil, nil, &tv)
586 took = time.Since(start)
587 if err == unix.EINTR {
588 t.Logf("Select interrupted after %v", took)
589 continue
590 } else if err != nil {
591 t.Fatalf("Select: %v", err)
592 }
593 if n != 0 {
594 t.Fatalf("Select: got %v ready file descriptors, expected 0", n)
595 }
596 break
597 }
598
599
600
601
602
603
604 if took < dur {
605 if runtime.GOOS == "linux" {
606 t.Errorf("Select: slept for %v, expected %v", took, dur)
607 } else {
608 t.Logf("Select: slept for %v, requested %v", took, dur)
609 }
610 }
611
612 rr, ww, err := os.Pipe()
613 if err != nil {
614 t.Fatal(err)
615 }
616 defer rr.Close()
617 defer ww.Close()
618
619 if _, err := ww.Write([]byte("HELLO GOPHER")); err != nil {
620 t.Fatal(err)
621 }
622
623 rFdSet := &unix.FdSet{}
624 fd := int(rr.Fd())
625 rFdSet.Set(fd)
626
627 for {
628 n, err := unix.Select(fd+1, rFdSet, nil, nil, nil)
629 if err == unix.EINTR {
630 t.Log("Select interrupted")
631 continue
632 } else if err != nil {
633 t.Fatalf("Select: %v", err)
634 }
635 if n != 1 {
636 t.Fatalf("Select: got %v ready file descriptors, expected 1", n)
637 }
638 break
639 }
640 }
641
642 func TestGetwd(t *testing.T) {
643 fd, err := os.Open(".")
644 if err != nil {
645 t.Fatalf("Open .: %s", err)
646 }
647 defer fd.Close()
648
649
650 dirs := []string{"/", "/usr/bin", "/etc", "/var", "/opt"}
651 switch runtime.GOOS {
652 case "android":
653 dirs = []string{"/", "/system/bin"}
654 case "ios":
655 dirs = []string{t.TempDir(), t.TempDir()}
656 }
657 oldwd := os.Getenv("PWD")
658 for _, d := range dirs {
659
660 fi, err := os.Stat(d)
661 if err != nil || !fi.IsDir() {
662 t.Logf("Test dir %s stat error (%v) or not a directory, skipping", d, err)
663 continue
664 }
665 check, err := filepath.EvalSymlinks(d)
666 if err != nil || check != d {
667 t.Logf("Test dir %s (%s) is symlink or other error (%v), skipping", d, check, err)
668 continue
669 }
670 err = os.Chdir(d)
671 if err != nil {
672 t.Fatalf("Chdir: %v", err)
673 }
674 pwd, err := unix.Getwd()
675 if err != nil {
676 t.Fatalf("Getwd in %s: %s", d, err)
677 }
678 os.Setenv("PWD", oldwd)
679 err = fd.Chdir()
680 if err != nil {
681
682
683
684 fmt.Fprintf(os.Stderr, "fchdir back to dot failed: %s\n", err)
685 os.Exit(1)
686 }
687 if pwd != d {
688 t.Fatalf("Getwd returned %q want %q", pwd, d)
689 }
690 }
691 }
692
693 func compareStat_t(t *testing.T, otherStat string, st1, st2 *unix.Stat_t) {
694 if st2.Dev != st1.Dev {
695 t.Errorf("%s/Fstatat: got dev %v, expected %v", otherStat, st2.Dev, st1.Dev)
696 }
697 if st2.Ino != st1.Ino {
698 t.Errorf("%s/Fstatat: got ino %v, expected %v", otherStat, st2.Ino, st1.Ino)
699 }
700 if st2.Mode != st1.Mode {
701 t.Errorf("%s/Fstatat: got mode %v, expected %v", otherStat, st2.Mode, st1.Mode)
702 }
703 if st2.Uid != st1.Uid {
704 t.Errorf("%s/Fstatat: got uid %v, expected %v", otherStat, st2.Uid, st1.Uid)
705 }
706 if st2.Gid != st1.Gid {
707 t.Errorf("%s/Fstatat: got gid %v, expected %v", otherStat, st2.Gid, st1.Gid)
708 }
709 if st2.Size != st1.Size {
710 t.Errorf("%s/Fstatat: got size %v, expected %v", otherStat, st2.Size, st1.Size)
711 }
712 }
713
714 func TestFstatat(t *testing.T) {
715 chtmpdir(t)
716
717 touch(t, "file1")
718
719 var st1 unix.Stat_t
720 err := unix.Stat("file1", &st1)
721 if err != nil {
722 t.Fatalf("Stat: %v", err)
723 }
724
725 var st2 unix.Stat_t
726 err = unix.Fstatat(unix.AT_FDCWD, "file1", &st2, 0)
727 if err != nil {
728 t.Fatalf("Fstatat: %v", err)
729 }
730
731 compareStat_t(t, "Stat", &st1, &st2)
732
733 err = os.Symlink("file1", "symlink1")
734 if err != nil {
735 t.Fatal(err)
736 }
737
738 err = unix.Lstat("symlink1", &st1)
739 if err != nil {
740 t.Fatalf("Lstat: %v", err)
741 }
742
743 err = unix.Fstatat(unix.AT_FDCWD, "symlink1", &st2, unix.AT_SYMLINK_NOFOLLOW)
744 if err != nil {
745 t.Fatalf("Fstatat: %v", err)
746 }
747
748 compareStat_t(t, "Lstat", &st1, &st2)
749 }
750
751 func TestFchmodat(t *testing.T) {
752 chtmpdir(t)
753
754 touch(t, "file1")
755 err := os.Symlink("file1", "symlink1")
756 if err != nil {
757 t.Fatal(err)
758 }
759
760 mode := os.FileMode(0444)
761 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), 0)
762 if err != nil {
763 t.Fatalf("Fchmodat: unexpected error: %v", err)
764 }
765
766 fi, err := os.Stat("file1")
767 if err != nil {
768 t.Fatal(err)
769 }
770
771 if fi.Mode() != mode {
772 t.Errorf("Fchmodat: failed to change file mode: expected %v, got %v", mode, fi.Mode())
773 }
774
775 mode = os.FileMode(0644)
776 didChmodSymlink := true
777 err = unix.Fchmodat(unix.AT_FDCWD, "symlink1", uint32(mode), unix.AT_SYMLINK_NOFOLLOW)
778 if err != nil {
779 if (runtime.GOOS == "android" || runtime.GOOS == "linux" ||
780 runtime.GOOS == "solaris" || runtime.GOOS == "illumos") && err == unix.EOPNOTSUPP {
781
782 didChmodSymlink = false
783 } else {
784 t.Fatalf("Fchmodat: unexpected error: %v", err)
785 }
786 }
787
788 if !didChmodSymlink {
789
790
791 mode = os.FileMode(0777)
792 }
793
794 var st unix.Stat_t
795 err = unix.Lstat("symlink1", &st)
796 if err != nil {
797 t.Fatal(err)
798 }
799
800 got := os.FileMode(st.Mode & 0777)
801 if got != mode {
802 t.Errorf("Fchmodat: failed to change symlink mode: expected %v, got %v", mode, got)
803 }
804 }
805
806 func TestMkdev(t *testing.T) {
807 major := uint32(42)
808 minor := uint32(7)
809 dev := unix.Mkdev(major, minor)
810
811 if unix.Major(dev) != major {
812 t.Errorf("Major(%#x) == %d, want %d", dev, unix.Major(dev), major)
813 }
814 if unix.Minor(dev) != minor {
815 t.Errorf("Minor(%#x) == %d, want %d", dev, unix.Minor(dev), minor)
816 }
817 }
818
819 func TestPipe(t *testing.T) {
820 const s = "hello"
821 var pipes [2]int
822 err := unix.Pipe(pipes[:])
823 if err != nil {
824 t.Fatalf("pipe: %v", err)
825 }
826 r := pipes[0]
827 w := pipes[1]
828 go func() {
829 n, err := unix.Write(w, []byte(s))
830 if err != nil {
831 t.Errorf("bad write: %v", err)
832 return
833 }
834 if n != len(s) {
835 t.Errorf("bad write count: %d", n)
836 return
837 }
838 err = unix.Close(w)
839 if err != nil {
840 t.Errorf("bad close: %v", err)
841 return
842 }
843 }()
844 var buf [10 + len(s)]byte
845 n, err := unix.Read(r, buf[:])
846 if err != nil {
847 t.Fatalf("bad read: %v", err)
848 }
849 if n != len(s) {
850 t.Fatalf("bad read count: %d", n)
851 }
852 if string(buf[:n]) != s {
853 t.Fatalf("bad contents: %s", string(buf[:n]))
854 }
855 err = unix.Close(r)
856 if err != nil {
857 t.Fatalf("bad close: %v", err)
858 }
859 }
860
861 func TestRenameat(t *testing.T) {
862 chtmpdir(t)
863
864 from, to := "renamefrom", "renameto"
865
866 touch(t, from)
867
868 err := unix.Renameat(unix.AT_FDCWD, from, unix.AT_FDCWD, to)
869 if err != nil {
870 t.Fatalf("Renameat: unexpected error: %v", err)
871 }
872
873 _, err = os.Stat(to)
874 if err != nil {
875 t.Error(err)
876 }
877
878 _, err = os.Stat(from)
879 if err == nil {
880 t.Errorf("Renameat: stat of renamed file %q unexpectedly succeeded", from)
881 }
882 }
883
884 func TestUtimesNanoAt(t *testing.T) {
885 chtmpdir(t)
886
887 symlink := "symlink1"
888 os.Remove(symlink)
889 err := os.Symlink("nonexisting", symlink)
890 if err != nil {
891 t.Fatal(err)
892 }
893
894
895
896 ts := []unix.Timespec{
897 {Sec: 1111, Nsec: 2000},
898 {Sec: 3333, Nsec: 4000},
899 }
900 err = unix.UtimesNanoAt(unix.AT_FDCWD, symlink, ts, unix.AT_SYMLINK_NOFOLLOW)
901 if err != nil {
902 t.Fatalf("UtimesNanoAt: %v", err)
903 }
904
905 var st unix.Stat_t
906 err = unix.Lstat(symlink, &st)
907 if err != nil {
908 t.Fatalf("Lstat: %v", err)
909 }
910
911
912 expected := ts[1]
913 if st.Mtim.Nsec == 0 {
914
915
916 expected.Nsec = 0
917 }
918 if st.Mtim != expected {
919 t.Errorf("UtimesNanoAt: wrong mtime: got %v, expected %v", st.Mtim, expected)
920 }
921 }
922
923 func TestSend(t *testing.T) {
924 ec := make(chan error, 2)
925 ts := []byte("HELLO GOPHER")
926
927 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
928 if err != nil {
929 t.Fatalf("Socketpair: %v", err)
930 }
931 defer unix.Close(fds[0])
932 defer unix.Close(fds[1])
933
934 go func() {
935 data := make([]byte, len(ts))
936
937 _, _, err := unix.Recvfrom(fds[1], data, 0)
938 if err != nil {
939 ec <- err
940 }
941 if !bytes.Equal(ts, data) {
942 ec <- fmt.Errorf("data sent != data received. Received %q", data)
943 }
944 ec <- nil
945 }()
946 err = unix.Send(fds[0], ts, 0)
947 if err != nil {
948 ec <- err
949 }
950
951 select {
952 case err = <-ec:
953 if err != nil {
954 t.Fatalf("Send: %v", err)
955 }
956 case <-time.After(2 * time.Second):
957 t.Fatal("Send: nothing received after 2 seconds")
958 }
959 }
960
961 func TestSendmsgBuffers(t *testing.T) {
962 fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM, 0)
963 if err != nil {
964 t.Fatal(err)
965 }
966 defer unix.Close(fds[0])
967 defer unix.Close(fds[1])
968
969 var wg sync.WaitGroup
970 wg.Add(1)
971 go func() {
972 defer wg.Done()
973 bufs := [][]byte{
974 make([]byte, 5),
975 nil,
976 make([]byte, 5),
977 }
978 n, oobn, recvflags, _, err := unix.RecvmsgBuffers(fds[1], bufs, nil, 0)
979 if err != nil {
980 t.Error(err)
981 return
982 }
983 if n != 10 {
984 t.Errorf("got %d bytes, want 10", n)
985 }
986 if oobn != 0 {
987 t.Errorf("got %d OOB bytes, want 0", oobn)
988 }
989 if recvflags != 0 {
990 t.Errorf("got flags %#x, want %#x", recvflags, 0)
991 }
992 want := [][]byte{
993 []byte("01234"),
994 nil,
995 []byte("56789"),
996 }
997 if !reflect.DeepEqual(bufs, want) {
998 t.Errorf("got data %q, want %q", bufs, want)
999 }
1000 }()
1001
1002 defer wg.Wait()
1003
1004 bufs := [][]byte{
1005 []byte("012"),
1006 []byte("34"),
1007 nil,
1008 []byte("5678"),
1009 []byte("9"),
1010 }
1011 n, err := unix.SendmsgBuffers(fds[0], bufs, nil, nil, 0)
1012 if err != nil {
1013 t.Fatal(err)
1014 }
1015 if n != 10 {
1016 t.Errorf("sent %d bytes, want 10", n)
1017 }
1018 }
1019
1020
1021 func TestRecvmsgControl(t *testing.T) {
1022 switch runtime.GOOS {
1023 case "solaris", "illumos":
1024
1025
1026
1027
1028
1029
1030 t.Skipf("skipping on %s", runtime.GOOS)
1031 }
1032
1033 fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0)
1034 if err != nil {
1035 t.Fatal(err)
1036 }
1037 defer unix.Close(fds[0])
1038 defer unix.Close(fds[1])
1039
1040 const payload = "hello"
1041
1042
1043
1044 go func() {
1045 f, err := os.Create(filepath.Join(t.TempDir(), "file"))
1046 if err != nil {
1047 t.Error(err)
1048 return
1049 }
1050 defer f.Close()
1051
1052 rc, err := f.SyscallConn()
1053 if err != nil {
1054 t.Error(err)
1055 return
1056 }
1057 var rights []byte
1058 err = rc.Control(func(fd uintptr) {
1059 rights = unix.UnixRights(int(fd))
1060 })
1061 if err != nil {
1062 t.Error(err)
1063 return
1064 }
1065
1066 _, err = unix.SendmsgN(fds[1], nil, rights, nil, 0)
1067 if err != nil {
1068 t.Error(err)
1069 }
1070 if _, err := unix.Write(fds[1], []byte(payload)); err != nil {
1071 t.Error(err)
1072 }
1073 }()
1074
1075
1076
1077
1078 cbuf := make([]byte, unix.CmsgSpace(4))
1079 _, cn, _, _, err := unix.Recvmsg(fds[0], nil, cbuf, 0)
1080 if err != nil {
1081 t.Fatal(err)
1082 }
1083 cbuf = cbuf[:cn]
1084
1085
1086
1087 buf := make([]byte, len(payload))
1088 n, err := unix.Read(fds[0], buf)
1089 if err != nil {
1090 t.Fatal(err)
1091 }
1092 buf = buf[:n]
1093 if payload != string(buf) {
1094 t.Errorf("read payload %q, want %q", buf, payload)
1095 }
1096
1097
1098
1099 cmsgs, err := unix.ParseSocketControlMessage(cbuf)
1100 if err != nil {
1101 t.Fatal(err)
1102 }
1103 if len(cmsgs) != 1 {
1104 t.Fatalf("got %d control messages, want 1", len(cmsgs))
1105 }
1106 cfds, err := unix.ParseUnixRights(&cmsgs[0])
1107 if err != nil {
1108 t.Fatal(err)
1109 }
1110 if len(cfds) != 1 {
1111 t.Fatalf("got %d fds, want 1", len(cfds))
1112 }
1113 defer unix.Close(cfds[0])
1114 }
1115
1116
1117 func mktmpfifo(t *testing.T) *os.File {
1118 t.Helper()
1119 err := unix.Mkfifo("fifo", 0666)
1120 if err != nil {
1121 t.Fatalf("mktmpfifo: failed to create FIFO: %v", err)
1122 }
1123
1124 f, err := os.OpenFile("fifo", os.O_RDWR, 0666)
1125 if err != nil {
1126 os.Remove("fifo")
1127 t.Fatal(err)
1128 }
1129 t.Cleanup(func() {
1130 f.Close()
1131 os.Remove("fifo")
1132 })
1133
1134 return f
1135 }
1136
1137
1138
1139 func touch(t *testing.T, name string) {
1140 t.Helper()
1141 f, err := os.Create(name)
1142 if err != nil {
1143 t.Fatal(err)
1144 }
1145 if err := f.Close(); err != nil {
1146 t.Fatal(err)
1147 }
1148 }
1149
1150
1151
1152 func chtmpdir(t *testing.T) {
1153 t.Helper()
1154 oldwd, err := os.Getwd()
1155 if err != nil {
1156 t.Fatal(err)
1157 }
1158 if err := os.Chdir(t.TempDir()); err != nil {
1159 t.Fatal(err)
1160 }
1161 t.Cleanup(func() {
1162 if err := os.Chdir(oldwd); err != nil {
1163 t.Fatal(err)
1164 }
1165 })
1166 }
1167
View as plain text