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