1
2
3
4
5
6
7 package unix_test
8
9 import (
10 "bufio"
11 "bytes"
12 "encoding/hex"
13 "errors"
14 "fmt"
15 "io"
16 "net"
17 "os"
18 "os/exec"
19 "path/filepath"
20 "runtime"
21 "runtime/debug"
22 "strconv"
23 "strings"
24 "syscall"
25 "testing"
26 "time"
27 "unsafe"
28
29 "golang.org/x/sys/unix"
30 )
31
32 func TestIoctlGetEthtoolDrvinfo(t *testing.T) {
33 if runtime.GOOS == "android" {
34 t.Skip("ethtool driver info is not available on android, skipping test")
35 }
36
37 s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
38 if err != nil {
39 t.Fatalf("failed to open socket: %v", err)
40 }
41 defer unix.Close(s)
42
43 ifis, err := net.Interfaces()
44 if err != nil {
45 t.Fatalf("failed to get network interfaces: %v", err)
46 }
47
48
49
50 for _, ifi := range ifis {
51 drv, err := unix.IoctlGetEthtoolDrvinfo(s, ifi.Name)
52 if err != nil {
53 if err == unix.EOPNOTSUPP {
54 continue
55 }
56
57 t.Fatalf("failed to get ethtool driver info for %q: %v", ifi.Name, err)
58 }
59
60
61 t.Logf("%s: %q", ifi.Name, string(bytes.TrimRight(drv.Driver[:], "\x00")))
62 }
63 }
64
65 func TestIoctlGetInt(t *testing.T) {
66 f, err := os.Open("/dev/random")
67 if err != nil {
68 t.Fatalf("failed to open device: %v", err)
69 }
70 defer f.Close()
71
72 v, err := unix.IoctlGetInt(int(f.Fd()), unix.RNDGETENTCNT)
73 if err != nil {
74 t.Fatalf("failed to perform ioctl: %v", err)
75 }
76
77 t.Logf("%d bits of entropy available", v)
78 }
79
80 func TestIoctlRetInt(t *testing.T) {
81 f, err := os.Open("/proc/self/ns/mnt")
82 if err != nil {
83 t.Skipf("skipping test, %v", err)
84 }
85 defer f.Close()
86
87 v, err := unix.IoctlRetInt(int(f.Fd()), unix.NS_GET_NSTYPE)
88 if err != nil {
89 if err == unix.ENOTTY {
90 t.Skipf("old kernel? (need Linux >= 4.11)")
91 }
92 t.Fatalf("failed to perform ioctl: %v", err)
93 }
94 if v != unix.CLONE_NEWNS {
95 t.Fatalf("unexpected return from ioctl; expected %v, got %v", v, unix.CLONE_NEWNS)
96 }
97 }
98
99 func TestIoctlGetRTCTime(t *testing.T) {
100 f, err := os.Open("/dev/rtc0")
101 if err != nil {
102 t.Skipf("skipping test, %v", err)
103 }
104 defer f.Close()
105
106 v, err := unix.IoctlGetRTCTime(int(f.Fd()))
107 if err != nil {
108 t.Fatalf("failed to perform ioctl: %v", err)
109 }
110
111 t.Logf("RTC time: %04d-%02d-%02d %02d:%02d:%02d", v.Year+1900, v.Mon+1, v.Mday, v.Hour, v.Min, v.Sec)
112 }
113
114 func TestIoctlGetRTCWkAlrm(t *testing.T) {
115 f, err := os.Open("/dev/rtc0")
116 if err != nil {
117 t.Skipf("skipping test, %v", err)
118 }
119 defer f.Close()
120
121 v, err := unix.IoctlGetRTCWkAlrm(int(f.Fd()))
122
123
124 if err == unix.EINVAL {
125 t.Skip("RTC_WKALM_RD ioctl not supported on this rtc, skipping test")
126 }
127
128 if err != nil {
129 t.Fatalf("failed to perform ioctl: %v", err)
130 }
131
132 t.Logf("RTC wake alarm enabled '%d'; time: %04d-%02d-%02d %02d:%02d:%02d",
133 v.Enabled, v.Time.Year+1900, v.Time.Mon+1, v.Time.Mday, v.Time.Hour, v.Time.Min, v.Time.Sec)
134 }
135
136 func TestIoctlIfreq(t *testing.T) {
137 s, err := unix.Socket(unix.AF_INET, unix.SOCK_STREAM, 0)
138 if err != nil {
139 t.Fatalf("failed to open socket: %v", err)
140 }
141 defer unix.Close(s)
142
143 ifis, err := net.Interfaces()
144 if err != nil {
145 t.Fatalf("failed to get network interfaces: %v", err)
146 }
147
148
149
150 for _, ifi := range ifis {
151 ifr, err := unix.NewIfreq(ifi.Name)
152 if err != nil {
153 t.Fatalf("failed to create ifreq for %q: %v", ifi.Name, err)
154 }
155
156 if err := unix.IoctlIfreq(s, unix.SIOCGIFINDEX, ifr); err != nil {
157 t.Fatalf("failed to get interface index for %q: %v", ifi.Name, err)
158 }
159
160 if want, got := ifi.Index, int(ifr.Uint32()); want != got {
161 t.Fatalf("unexpected interface index for %q: got: %d, want: %d",
162 ifi.Name, got, want)
163 }
164
165 if want, got := ifi.Name, ifr.Name(); want != got {
166 t.Fatalf("unexpected interface name for index %d: got: %q, want: %q",
167 ifi.Index, got, want)
168 }
169
170 wantIP, ok := firstIPv4(t, &ifi)
171 if err := unix.IoctlIfreq(s, unix.SIOCGIFADDR, ifr); err != nil {
172
173 if err != unix.EADDRNOTAVAIL {
174 t.Fatalf("failed to get IPv4 address for %q: %v", ifi.Name, err)
175 }
176
177
178
179 if ok {
180 t.Fatalf("found IPv4 address %q for %q but ioctl returned none", wantIP, ifi.Name)
181 }
182
183 continue
184 }
185
186
187 addr, err := ifr.Inet4Addr()
188 if err != nil {
189 t.Fatalf("failed to get ifreq IPv4 address: %v", err)
190 }
191
192 if want, got := wantIP, addr; !want.Equal(got) {
193 t.Fatalf("unexpected first IPv4 address for %q: got: %q, want: %q",
194 ifi.Name, got, want)
195 }
196 }
197 }
198
199
200
201 func firstIPv4(t *testing.T, ifi *net.Interface) (net.IP, bool) {
202 t.Helper()
203
204 addrs, err := ifi.Addrs()
205 if err != nil {
206 t.Fatalf("failed to get interface %q addresses: %v", ifi.Name, err)
207 }
208
209 for _, a := range addrs {
210
211 ipn, ok := a.(*net.IPNet)
212 if !ok || ipn.IP.To4() == nil {
213 continue
214 }
215
216 return ipn.IP, true
217 }
218
219 return nil, false
220 }
221
222 func TestPidfd(t *testing.T) {
223
224
225 cmd := exec.Command("sleep", "1h")
226 if err := cmd.Start(); err != nil {
227 t.Fatalf("failed to exec sleep: %v", err)
228 }
229
230 fd, err := unix.PidfdOpen(cmd.Process.Pid, 0)
231 if err != nil {
232
233 if errors.Is(err, unix.ENOSYS) {
234 t.Skipf("skipping, pidfd_open is not implemented: %v", err)
235 }
236
237 t.Fatalf("failed to open child pidfd: %v", err)
238 }
239 defer unix.Close(fd)
240
241
242 if err := unix.Waitid(unix.P_PIDFD, fd, nil, unix.WEXITED|unix.WNOHANG, nil); err != nil {
243 if errors.Is(err, unix.EINVAL) {
244 t.Skip("skipping due to waitid EINVAL, see https://go.dev/issues/52014")
245 }
246
247 t.Fatalf("failed to check for child exit: %v", err)
248 }
249
250 const want = unix.SIGHUP
251 if err := unix.PidfdSendSignal(fd, want, nil, 0); err != nil {
252 t.Fatalf("failed to signal child process: %v", err)
253 }
254
255
256 var eerr *exec.ExitError
257 if err := cmd.Wait(); !errors.As(err, &eerr) {
258 t.Fatalf("child process terminated but did not return an exit error: %v", err)
259 }
260
261 if err := unix.Waitid(unix.P_PIDFD, fd, nil, unix.WEXITED, nil); !errors.Is(err, unix.ECHILD) {
262 t.Fatalf("expected ECHILD for final waitid, but got: %v", err)
263 }
264
265 ws, ok := eerr.Sys().(syscall.WaitStatus)
266 if !ok {
267 t.Fatalf("expected syscall.WaitStatus value, but got: %#T", eerr.Sys())
268 }
269
270 if got := ws.Signal(); got != want {
271 t.Fatalf("unexpected child exit signal, got: %s, want: %s", got, want)
272 }
273 }
274
275 func TestPpoll(t *testing.T) {
276 if runtime.GOOS == "android" {
277 t.Skip("mkfifo syscall is not available on android, skipping test")
278 }
279
280 chtmpdir(t)
281 f := mktmpfifo(t)
282
283 const timeout = 100 * time.Millisecond
284
285 ok := make(chan bool, 1)
286 go func() {
287 select {
288 case <-time.After(10 * timeout):
289 t.Errorf("Ppoll: failed to timeout after %d", 10*timeout)
290 case <-ok:
291 }
292 }()
293
294 fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}}
295 timeoutTs := unix.NsecToTimespec(int64(timeout))
296 n, err := unix.Ppoll(fds, &timeoutTs, nil)
297 ok <- true
298 if err != nil {
299 t.Errorf("Ppoll: unexpected error: %v", err)
300 return
301 }
302 if n != 0 {
303 t.Errorf("Ppoll: wrong number of events: got %v, expected %v", n, 0)
304 return
305 }
306 }
307
308 func TestTime(t *testing.T) {
309 var ut unix.Time_t
310 ut2, err := unix.Time(&ut)
311 if err != nil {
312 t.Fatalf("Time: %v", err)
313 }
314 if ut != ut2 {
315 t.Errorf("Time: return value %v should be equal to argument %v", ut2, ut)
316 }
317
318 var now time.Time
319
320 for i := 0; i < 10; i++ {
321 ut, err = unix.Time(nil)
322 if err != nil {
323 t.Fatalf("Time: %v", err)
324 }
325
326 now = time.Now()
327 diff := int64(ut) - now.Unix()
328 if -1 <= diff && diff <= 1 {
329 return
330 }
331 }
332
333 t.Errorf("Time: return value %v should be nearly equal to time.Now().Unix() %v±1", ut, now.Unix())
334 }
335
336 func TestUtime(t *testing.T) {
337 chtmpdir(t)
338
339 touch(t, "file1")
340
341 buf := &unix.Utimbuf{
342 Modtime: 12345,
343 }
344
345 err := unix.Utime("file1", buf)
346 if err != nil {
347 t.Fatalf("Utime: %v", err)
348 }
349
350 fi, err := os.Stat("file1")
351 if err != nil {
352 t.Fatal(err)
353 }
354
355 if fi.ModTime().Unix() != 12345 {
356 t.Errorf("Utime: failed to change modtime: expected %v, got %v", 12345, fi.ModTime().Unix())
357 }
358 }
359
360 func TestRlimitAs(t *testing.T) {
361
362 defer debug.SetGCPercent(debug.SetGCPercent(-1))
363
364 var rlim unix.Rlimit
365 err := unix.Getrlimit(unix.RLIMIT_AS, &rlim)
366 if err != nil {
367 t.Fatalf("Getrlimit: %v", err)
368 }
369 var zero unix.Rlimit
370 if zero == rlim {
371 t.Fatalf("Getrlimit: got zero value %#v", rlim)
372 }
373 set := rlim
374 set.Cur = uint64(unix.Getpagesize())
375 err = unix.Setrlimit(unix.RLIMIT_AS, &set)
376 if err != nil {
377 t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
378 }
379
380
381
382 _, err = unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
383 if err == nil {
384 t.Fatal("Mmap: unexpectedly succeeded after setting RLIMIT_AS")
385 }
386
387 err = unix.Setrlimit(unix.RLIMIT_AS, &rlim)
388 if err != nil {
389 t.Fatalf("Setrlimit: restore failed: %#v %v", rlim, err)
390 }
391
392 b, err := unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
393 if err != nil {
394 t.Fatalf("Mmap: %v", err)
395 }
396 err = unix.Munmap(b)
397 if err != nil {
398 t.Fatalf("Munmap: %v", err)
399 }
400 }
401
402 func TestPselect(t *testing.T) {
403 for {
404 n, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, nil)
405 if err == unix.EINTR {
406 t.Logf("Pselect interrupted")
407 continue
408 } else if err != nil {
409 t.Fatalf("Pselect: %v", err)
410 }
411 if n != 0 {
412 t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
413 }
414 break
415 }
416
417 dur := 2500 * time.Microsecond
418 var took time.Duration
419 for {
420
421
422
423 ts := unix.NsecToTimespec(int64(dur))
424 start := time.Now()
425 n, err := unix.Pselect(0, nil, nil, nil, &ts, nil)
426 took = time.Since(start)
427 if err == unix.EINTR {
428 t.Logf("Pselect interrupted after %v", took)
429 continue
430 } else if err != nil {
431 t.Fatalf("Pselect: %v", err)
432 }
433 if n != 0 {
434 t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
435 }
436 break
437 }
438
439
440
441 if took < dur*2/3 {
442 t.Errorf("Pselect: got %v timeout, expected at least %v", took, dur)
443 }
444 }
445
446 func TestPselectWithSigmask(t *testing.T) {
447 var sigmask unix.Sigset_t
448 sigmask.Val[0] |= 1 << (uint(unix.SIGUSR1) - 1)
449 for {
450 n, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, &sigmask)
451 if err == unix.EINTR {
452 t.Logf("Pselect interrupted")
453 continue
454 } else if err != nil {
455 t.Fatalf("Pselect: %v", err)
456 }
457 if n != 0 {
458 t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
459 }
460 break
461 }
462 }
463
464 func TestSchedSetaffinity(t *testing.T) {
465 var newMask unix.CPUSet
466 newMask.Zero()
467 if newMask.Count() != 0 {
468 t.Errorf("CpuZero: didn't zero CPU set: %v", newMask)
469 }
470 cpu := 1
471 newMask.Set(cpu)
472 if newMask.Count() != 1 || !newMask.IsSet(cpu) {
473 t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
474 }
475 cpu = 5
476 newMask.Set(cpu)
477 if newMask.Count() != 2 || !newMask.IsSet(cpu) {
478 t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
479 }
480 newMask.Clear(cpu)
481 if newMask.Count() != 1 || newMask.IsSet(cpu) {
482 t.Errorf("CpuClr: didn't clear CPU %d in set: %v", cpu, newMask)
483 }
484
485 runtime.LockOSThread()
486 defer runtime.UnlockOSThread()
487
488 var oldMask unix.CPUSet
489 err := unix.SchedGetaffinity(0, &oldMask)
490 if err != nil {
491 t.Fatalf("SchedGetaffinity: %v", err)
492 }
493
494 if runtime.NumCPU() < 2 {
495 t.Skip("skipping setaffinity tests on single CPU system")
496 }
497 if runtime.GOOS == "android" {
498 t.Skip("skipping setaffinity tests on android")
499 }
500
501
502
503
504
505 cpu = 1
506 if !oldMask.IsSet(cpu) {
507 newMask.Zero()
508 for i := 0; i < len(oldMask); i++ {
509 if oldMask.IsSet(i) {
510 newMask.Set(i)
511 break
512 }
513 }
514 if newMask.Count() == 0 {
515 t.Skip("skipping setaffinity tests if CPU not available")
516 }
517 }
518
519 err = unix.SchedSetaffinity(0, &newMask)
520 if err != nil {
521 t.Fatalf("SchedSetaffinity: %v", err)
522 }
523
524 var gotMask unix.CPUSet
525 err = unix.SchedGetaffinity(0, &gotMask)
526 if err != nil {
527 t.Fatalf("SchedGetaffinity: %v", err)
528 }
529
530 if gotMask != newMask {
531 t.Errorf("SchedSetaffinity: returned affinity mask does not match set affinity mask")
532 }
533
534
535 err = unix.SchedSetaffinity(0, &oldMask)
536 if err != nil {
537 t.Fatalf("SchedSetaffinity: %v", err)
538 }
539 }
540
541 func TestStatx(t *testing.T) {
542 var stx unix.Statx_t
543 err := unix.Statx(unix.AT_FDCWD, ".", 0, 0, &stx)
544 if err == unix.ENOSYS || err == unix.EPERM {
545 t.Skip("statx syscall is not available, skipping test")
546 } else if err != nil {
547 t.Fatalf("Statx: %v", err)
548 }
549
550 chtmpdir(t)
551 touch(t, "file1")
552
553 var st unix.Stat_t
554 err = unix.Stat("file1", &st)
555 if err != nil {
556 t.Fatalf("Stat: %v", err)
557 }
558
559 flags := unix.AT_STATX_SYNC_AS_STAT
560 err = unix.Statx(unix.AT_FDCWD, "file1", flags, unix.STATX_ALL, &stx)
561 if err != nil {
562 t.Fatalf("Statx: %v", err)
563 }
564
565 if uint32(stx.Mode) != st.Mode {
566 t.Errorf("Statx: returned stat mode does not match Stat")
567 }
568
569 ctime := unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
570 mtime := unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
571
572 if stx.Ctime != ctime {
573 t.Errorf("Statx: returned stat ctime does not match Stat")
574 }
575 if stx.Mtime != mtime {
576 t.Errorf("Statx: returned stat mtime does not match Stat")
577 }
578
579 err = os.Symlink("file1", "symlink1")
580 if err != nil {
581 t.Fatal(err)
582 }
583
584 err = unix.Lstat("symlink1", &st)
585 if err != nil {
586 t.Fatalf("Lstat: %v", err)
587 }
588
589 err = unix.Statx(unix.AT_FDCWD, "symlink1", flags, unix.STATX_BASIC_STATS, &stx)
590 if err != nil {
591 t.Fatalf("Statx: %v", err)
592 }
593
594
595 if stx.Mode&unix.S_IFREG == 0 {
596 t.Errorf("Statx: didn't follow symlink")
597 }
598
599 err = unix.Statx(unix.AT_FDCWD, "symlink1", flags|unix.AT_SYMLINK_NOFOLLOW, unix.STATX_ALL, &stx)
600 if err != nil {
601 t.Fatalf("Statx: %v", err)
602 }
603
604
605 if stx.Mode&unix.S_IFLNK == 0 {
606 t.Errorf("Statx: unexpectedly followed symlink")
607 }
608 if uint32(stx.Mode) != st.Mode {
609 t.Errorf("Statx: returned stat mode does not match Lstat")
610 }
611
612 ctime = unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
613 mtime = unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
614
615 if stx.Ctime != ctime {
616 t.Errorf("Statx: returned stat ctime does not match Lstat")
617 }
618 if stx.Mtime != mtime {
619 t.Errorf("Statx: returned stat mtime does not match Lstat")
620 }
621 }
622
623
624
625 func stringsFromByteSlice(buf []byte) []string {
626 var result []string
627 off := 0
628 for i, b := range buf {
629 if b == 0 {
630 result = append(result, string(buf[off:i]))
631 off = i + 1
632 }
633 }
634 return result
635 }
636
637 func TestFaccessat(t *testing.T) {
638 chtmpdir(t)
639 touch(t, "file1")
640
641 err := unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 0)
642 if err != nil {
643 t.Errorf("Faccessat: unexpected error: %v", err)
644 }
645
646 err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 2)
647 if err != unix.EINVAL {
648 t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
649 }
650
651 err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_EACCESS)
652 if err != nil {
653 t.Errorf("Faccessat: unexpected error: %v", err)
654 }
655
656 err = os.Symlink("file1", "symlink1")
657 if err != nil {
658 t.Fatal(err)
659 }
660
661 err = unix.Faccessat(unix.AT_FDCWD, "symlink1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
662 if err != nil {
663 t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err)
664 }
665
666
667
668
669
670
671 err = unix.Fchmodat(unix.AT_FDCWD, "file1", 0, 0)
672 if err != nil {
673 t.Errorf("Fchmodat: unexpected error %v", err)
674 }
675
676 err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.F_OK, unix.AT_SYMLINK_NOFOLLOW)
677 if err != nil {
678 t.Errorf("Faccessat: unexpected error: %v", err)
679 }
680
681 err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
682 if err != unix.EACCES {
683 if unix.Getuid() != 0 {
684 t.Errorf("Faccessat: unexpected error: %v, want EACCES", err)
685 }
686 }
687 }
688
689 func TestSyncFileRange(t *testing.T) {
690 file, err := os.Create(filepath.Join(t.TempDir(), t.Name()))
691 if err != nil {
692 t.Fatal(err)
693 }
694 defer file.Close()
695
696 err = unix.SyncFileRange(int(file.Fd()), 0, 0, 0)
697 if err == unix.ENOSYS || err == unix.EPERM {
698 t.Skip("sync_file_range syscall is not available, skipping test")
699 } else if err != nil {
700 t.Fatalf("SyncFileRange: %v", err)
701 }
702
703
704 flags := 0xf00
705 err = unix.SyncFileRange(int(file.Fd()), 0, 0, flags)
706 if err != unix.EINVAL {
707 t.Fatalf("SyncFileRange: unexpected error: %v, want EINVAL", err)
708 }
709 }
710
711 func TestClockNanosleep(t *testing.T) {
712 delay := 50 * time.Millisecond
713
714
715 start := time.Now()
716 rel := unix.NsecToTimespec(delay.Nanoseconds())
717 remain := unix.Timespec{}
718 for {
719 err := unix.ClockNanosleep(unix.CLOCK_MONOTONIC, 0, &rel, &remain)
720 if err == unix.ENOSYS || err == unix.EPERM {
721 t.Skip("clock_nanosleep syscall is not available, skipping test")
722 } else if err == unix.EINTR {
723 t.Logf("ClockNanosleep interrupted after %v", time.Since(start))
724 rel = remain
725 continue
726 } else if err != nil {
727 t.Errorf("ClockNanosleep(CLOCK_MONOTONIC, 0, %#v, nil) = %v", &rel, err)
728 } else if slept := time.Since(start); slept < delay {
729 t.Errorf("ClockNanosleep(CLOCK_MONOTONIC, 0, %#v, nil) slept only %v", &rel, slept)
730 }
731 break
732 }
733
734
735 for {
736 start = time.Now()
737 until := start.Add(delay)
738 abs := unix.NsecToTimespec(until.UnixNano())
739 err := unix.ClockNanosleep(unix.CLOCK_REALTIME, unix.TIMER_ABSTIME, &abs, nil)
740 if err == unix.EINTR {
741 t.Logf("ClockNanosleep interrupted after %v", time.Since(start))
742 continue
743 } else if err != nil {
744 t.Errorf("ClockNanosleep(CLOCK_REALTIME, TIMER_ABSTIME, %#v (=%v), nil) = %v", &abs, until, err)
745 } else {
746
747
748
749
750
751
752
753
754
755
756
757
758 if now := time.Now(); now.Before(until) && now.Round(0).Before(until) {
759 t.Errorf("ClockNanosleep(CLOCK_REALTIME, TIMER_ABSTIME, %#v (=%v), nil) slept only until %v", &abs, until, now)
760 }
761 }
762 break
763 }
764
765
766 err := unix.ClockNanosleep(unix.CLOCK_THREAD_CPUTIME_ID, 0, &rel, nil)
767 if err != unix.EINVAL && err != unix.EOPNOTSUPP {
768 t.Errorf("ClockNanosleep(CLOCK_THREAD_CPUTIME_ID, 0, %#v, nil) = %v, want EINVAL or EOPNOTSUPP", &rel, err)
769 }
770 }
771
772 func TestOpenByHandleAt(t *testing.T) {
773 skipIfNotSupported := func(t *testing.T, name string, err error) {
774 if err == unix.EPERM {
775 t.Skipf("skipping %s test without CAP_DAC_READ_SEARCH", name)
776 }
777 if err == unix.ENOSYS {
778 t.Skipf("%s system call not available", name)
779 }
780 if err == unix.EOPNOTSUPP {
781 t.Skipf("%s not supported on this filesystem", name)
782 }
783 }
784
785 h, mountID, err := unix.NameToHandleAt(unix.AT_FDCWD, "syscall_linux_test.go", 0)
786 if err != nil {
787 skipIfNotSupported(t, "name_to_handle_at", err)
788 t.Fatalf("NameToHandleAt: %v", err)
789 }
790 t.Logf("mountID: %v, handle: size=%d, type=%d, bytes=%q", mountID,
791 h.Size(), h.Type(), h.Bytes())
792 mount, err := openMountByID(mountID)
793 if err != nil {
794 t.Fatalf("openMountByID: %v", err)
795 }
796 defer mount.Close()
797
798 for _, clone := range []bool{false, true} {
799 t.Run("clone="+strconv.FormatBool(clone), func(t *testing.T) {
800 if clone {
801 h = unix.NewFileHandle(h.Type(), h.Bytes())
802 }
803 fd, err := unix.OpenByHandleAt(int(mount.Fd()), h, unix.O_RDONLY)
804 skipIfNotSupported(t, "open_by_handle_at", err)
805 if err != nil {
806 t.Fatalf("OpenByHandleAt: %v", err)
807 }
808 t.Logf("opened fd %v", fd)
809 f := os.NewFile(uintptr(fd), "")
810 defer f.Close()
811
812 slurp, err := io.ReadAll(f)
813 if err != nil {
814 t.Fatal(err)
815 }
816 const substr = "Some substring for a test."
817 if !strings.Contains(string(slurp), substr) {
818 t.Errorf("didn't find substring %q in opened file; read %d bytes", substr, len(slurp))
819 }
820 })
821 }
822 }
823
824 func openMountByID(mountID int) (f *os.File, err error) {
825 mi, err := os.Open("/proc/self/mountinfo")
826 if err != nil {
827 return nil, err
828 }
829 defer mi.Close()
830 bs := bufio.NewScanner(mi)
831 wantPrefix := []byte(fmt.Sprintf("%v ", mountID))
832 for bs.Scan() {
833 if !bytes.HasPrefix(bs.Bytes(), wantPrefix) {
834 continue
835 }
836 fields := strings.Fields(bs.Text())
837 dev := fields[4]
838 return os.Open(dev)
839 }
840 if err := bs.Err(); err != nil {
841 return nil, err
842 }
843 return nil, errors.New("mountID not found")
844 }
845
846 func TestEpoll(t *testing.T) {
847 efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
848 if err != nil {
849 t.Fatalf("EpollCreate1: %v", err)
850 }
851 defer unix.Close(efd)
852
853 r, w, err := os.Pipe()
854 if err != nil {
855 t.Fatal(err)
856 }
857 defer r.Close()
858 defer w.Close()
859
860 fd := int(r.Fd())
861 ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
862
863 err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
864 if err != nil {
865 t.Fatalf("EpollCtl: %v", err)
866 }
867
868 if _, err := w.Write([]byte("HELLO GOPHER")); err != nil {
869 t.Fatal(err)
870 }
871
872 events := make([]unix.EpollEvent, 128)
873 n, err := unix.EpollWait(efd, events, 1)
874 if err != nil {
875 t.Fatalf("EpollWait: %v", err)
876 }
877
878 if n != 1 {
879 t.Errorf("EpollWait: wrong number of events: got %v, expected 1", n)
880 }
881
882 got := int(events[0].Fd)
883 if got != fd {
884 t.Errorf("EpollWait: wrong Fd in event: got %v, expected %v", got, fd)
885 }
886 }
887
888 func TestPrctlRetInt(t *testing.T) {
889 skipc := make(chan bool, 1)
890 skip := func() {
891 skipc <- true
892 runtime.Goexit()
893 }
894
895 go func() {
896
897
898 runtime.LockOSThread()
899 defer close(skipc)
900
901 err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
902 if err != nil {
903 t.Logf("Prctl: %v, skipping test", err)
904 skip()
905 }
906
907 v, err := unix.PrctlRetInt(unix.PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)
908 if err != nil {
909 t.Errorf("failed to perform prctl: %v", err)
910 }
911 if v != 1 {
912 t.Errorf("unexpected return from prctl; got %v, expected %v", v, 1)
913 }
914 }()
915
916 if <-skipc {
917 t.SkipNow()
918 }
919 }
920
921 func TestTimerfd(t *testing.T) {
922 var now unix.Timespec
923 if err := unix.ClockGettime(unix.CLOCK_REALTIME, &now); err != nil {
924 t.Fatalf("ClockGettime: %v", err)
925 }
926
927 tfd, err := unix.TimerfdCreate(unix.CLOCK_REALTIME, 0)
928 if err == unix.ENOSYS {
929 t.Skip("timerfd_create system call not implemented")
930 } else if err != nil {
931 t.Fatalf("TimerfdCreate: %v", err)
932 }
933 defer unix.Close(tfd)
934
935 var timeSpec unix.ItimerSpec
936 if err := unix.TimerfdGettime(tfd, &timeSpec); err != nil {
937 t.Fatalf("TimerfdGettime: %v", err)
938 }
939
940 if timeSpec.Value.Nsec != 0 || timeSpec.Value.Sec != 0 {
941 t.Fatalf("TimerfdGettime: timer is already set, but shouldn't be")
942 }
943
944 timeSpec = unix.ItimerSpec{
945 Interval: unix.NsecToTimespec(int64(time.Millisecond)),
946 Value: now,
947 }
948
949 if err := unix.TimerfdSettime(tfd, unix.TFD_TIMER_ABSTIME, &timeSpec, nil); err != nil {
950 t.Fatalf("TimerfdSettime: %v", err)
951 }
952
953 const totalTicks = 10
954 const bufferLength = 8
955
956 buffer := make([]byte, bufferLength)
957
958 var count uint64 = 0
959 for count < totalTicks {
960 n, err := unix.Read(tfd, buffer)
961 if err != nil {
962 t.Fatalf("Timerfd: %v", err)
963 } else if n != bufferLength {
964 t.Fatalf("Timerfd: got %d bytes from timerfd, expected %d bytes", n, bufferLength)
965 }
966
967 count += *(*uint64)(unsafe.Pointer(&buffer))
968 }
969 }
970
971 func TestOpenat2(t *testing.T) {
972 how := &unix.OpenHow{
973 Flags: unix.O_RDONLY,
974 }
975 fd, err := unix.Openat2(unix.AT_FDCWD, ".", how)
976 if err != nil {
977 if err == unix.ENOSYS || err == unix.EPERM {
978 t.Skipf("openat2: %v (old kernel? need Linux >= 5.6)", err)
979 }
980 t.Fatalf("openat2: %v", err)
981 }
982 if err := unix.Close(fd); err != nil {
983 t.Fatalf("close: %v", err)
984 }
985
986
987 subdir := filepath.Join(t.TempDir(), "dir")
988 if err := os.Mkdir(subdir, 0755); err != nil {
989 t.Fatal(err)
990 }
991 symlink := filepath.Join(subdir, "symlink")
992 if err := os.Symlink("../", symlink); err != nil {
993 t.Fatal(err)
994 }
995
996 dirfd, err := unix.Open(subdir, unix.O_RDONLY, 0)
997 if err != nil {
998 t.Fatalf("open(%q): %v", subdir, err)
999 }
1000 defer unix.Close(dirfd)
1001
1002
1003 fd, err = unix.Openat2(dirfd, "symlink", how)
1004 if err != nil {
1005 t.Errorf("Openat2 should succeed, got %v", err)
1006 }
1007 if err := unix.Close(fd); err != nil {
1008 t.Fatalf("close: %v", err)
1009 }
1010
1011
1012 how.Resolve = unix.RESOLVE_BENEATH
1013 fd, err = unix.Openat2(dirfd, "symlink", how)
1014 if err == nil {
1015 if err := unix.Close(fd); err != nil {
1016 t.Fatalf("close: %v", err)
1017 }
1018 }
1019 if err != unix.EXDEV {
1020 t.Errorf("Openat2 should fail with EXDEV, got %v", err)
1021 }
1022 }
1023
1024 func TestIoctlFileDedupeRange(t *testing.T) {
1025 dir := t.TempDir()
1026 f1, err := os.Create(filepath.Join(dir, "f1"))
1027 if err != nil {
1028 t.Fatal(err)
1029 }
1030 defer f1.Close()
1031
1032
1033 data := make([]byte, 4096)
1034
1035 for i := 0; i < 2; i += 1 {
1036 _, err = f1.Write(data)
1037 if err != nil {
1038 t.Fatal(err)
1039 }
1040 }
1041
1042 f2, err := os.Create(filepath.Join(dir, "f2"))
1043 if err != nil {
1044 t.Fatal(err)
1045 }
1046 defer f2.Close()
1047
1048 for i := 0; i < 2; i += 1 {
1049
1050 if i == 1 {
1051 data[1] = 1
1052 }
1053
1054 _, err = f2.Write(data)
1055 if err != nil {
1056 t.Fatal(err)
1057 }
1058 }
1059
1060 dedupe := unix.FileDedupeRange{
1061 Src_offset: uint64(0),
1062 Src_length: uint64(4096),
1063 Info: []unix.FileDedupeRangeInfo{
1064 unix.FileDedupeRangeInfo{
1065 Dest_fd: int64(f2.Fd()),
1066 Dest_offset: uint64(0),
1067 },
1068 unix.FileDedupeRangeInfo{
1069 Dest_fd: int64(f2.Fd()),
1070 Dest_offset: uint64(4096),
1071 },
1072 }}
1073
1074 err = unix.IoctlFileDedupeRange(int(f1.Fd()), &dedupe)
1075 if err == unix.EOPNOTSUPP || err == unix.EINVAL || err == unix.ENOTTY {
1076 t.Skip("deduplication not supported on this filesystem")
1077 } else if err != nil {
1078 t.Fatal(err)
1079 }
1080
1081
1082 if dedupe.Info[0].Status < 0 {
1083 errno := unix.Errno(-dedupe.Info[0].Status)
1084 if errno == unix.EINVAL {
1085 t.Skip("deduplication not supported on this filesystem")
1086 }
1087 t.Errorf("Unexpected error in FileDedupeRange: %s", unix.ErrnoName(errno))
1088 } else if dedupe.Info[0].Status == unix.FILE_DEDUPE_RANGE_DIFFERS {
1089 t.Errorf("Unexpected different bytes in FileDedupeRange")
1090 }
1091 if dedupe.Info[0].Bytes_deduped != 4096 {
1092 t.Errorf("Unexpected amount of bytes deduped %v != %v",
1093 dedupe.Info[0].Bytes_deduped, 4096)
1094 }
1095
1096
1097 if dedupe.Info[1].Status < 0 {
1098 errno := unix.Errno(-dedupe.Info[1].Status)
1099 if errno == unix.EINVAL {
1100 t.Skip("deduplication not supported on this filesystem")
1101 }
1102 t.Errorf("Unexpected error in FileDedupeRange: %s", unix.ErrnoName(errno))
1103 } else if dedupe.Info[1].Status == unix.FILE_DEDUPE_RANGE_SAME {
1104 t.Errorf("Unexpected equal bytes in FileDedupeRange")
1105 }
1106 if dedupe.Info[1].Bytes_deduped != 0 {
1107 t.Errorf("Unexpected amount of bytes deduped %v != %v",
1108 dedupe.Info[1].Bytes_deduped, 0)
1109 }
1110 }
1111
1112
1113
1114 func TestPwritevOffsets(t *testing.T) {
1115 path := filepath.Join(t.TempDir(), "x.txt")
1116
1117 f, err := os.Create(path)
1118 if err != nil {
1119 t.Fatal(err)
1120 }
1121 t.Cleanup(func() { f.Close() })
1122
1123 const (
1124 off = 20
1125 )
1126 b := [][]byte{{byte(0)}}
1127 n, err := unix.Pwritev(int(f.Fd()), b, off)
1128 if err != nil {
1129 t.Fatal(err)
1130 }
1131 if n != len(b) {
1132 t.Fatalf("expected to write %d, wrote %d", len(b), n)
1133 }
1134
1135 info, err := f.Stat()
1136 if err != nil {
1137 t.Fatal(err)
1138 }
1139 want := off + int64(len(b))
1140 if info.Size() != want {
1141 t.Fatalf("expected size to be %d, got %d", want, info.Size())
1142 }
1143 }
1144
1145 func TestReadvAllocate(t *testing.T) {
1146 f, err := os.Create(filepath.Join(t.TempDir(), "test"))
1147 if err != nil {
1148 t.Fatal(err)
1149 }
1150 t.Cleanup(func() { f.Close() })
1151
1152 test := func(name string, fn func(fd int)) {
1153 n := int(testing.AllocsPerRun(100, func() {
1154 fn(int(f.Fd()))
1155 }))
1156 if n != 0 {
1157 t.Errorf("%q got %d allocations, want 0", name, n)
1158 }
1159 }
1160
1161 iovs := make([][]byte, 8)
1162 for i := range iovs {
1163 iovs[i] = []byte{'A'}
1164 }
1165
1166 test("Writev", func(fd int) {
1167 unix.Writev(fd, iovs)
1168 })
1169 test("Pwritev", func(fd int) {
1170 unix.Pwritev(fd, iovs, 0)
1171 })
1172 test("Pwritev2", func(fd int) {
1173 unix.Pwritev2(fd, iovs, 0, 0)
1174 })
1175 test("Readv", func(fd int) {
1176 unix.Readv(fd, iovs)
1177 })
1178 test("Preadv", func(fd int) {
1179 unix.Preadv(fd, iovs, 0)
1180 })
1181 test("Preadv2", func(fd int) {
1182 unix.Preadv2(fd, iovs, 0, 0)
1183 })
1184 }
1185
1186 func TestSockaddrALG(t *testing.T) {
1187
1188 fd, err := unix.Socket(unix.AF_ALG, unix.SOCK_SEQPACKET, 0)
1189 if err != nil {
1190 t.Skip("socket(AF_ALG):", err)
1191 }
1192 defer unix.Close(fd)
1193 addr := &unix.SockaddrALG{Type: "hash", Name: "sha1"}
1194 if err := unix.Bind(fd, addr); err != nil {
1195 t.Fatal("bind:", err)
1196 }
1197
1198
1199 hashfd, _, errno := unix.Syscall6(unix.SYS_ACCEPT4, uintptr(fd), 0, 0, 0, 0, 0)
1200 if errno != 0 {
1201 t.Fatal("accept:", errno)
1202 }
1203
1204 hash := os.NewFile(hashfd, "sha1")
1205 defer hash.Close()
1206
1207
1208 const (
1209 input = "Hello, world."
1210 exp = "2ae01472317d1935a84797ec1983ae243fc6aa28"
1211 )
1212 if _, err := hash.WriteString(input); err != nil {
1213 t.Fatal(err)
1214 }
1215 b := make([]byte, 20)
1216 if _, err := hash.Read(b); err != nil {
1217 t.Fatal(err)
1218 }
1219 got := hex.EncodeToString(b)
1220 if got != exp {
1221 t.Fatalf("got: %q, want: %q", got, exp)
1222 }
1223 }
1224
View as plain text