github.com/xingly-cn/shorturl-go@v0.0.0-20220110130535-e21de4659f74/pkg/mod/golang.org/x/sys@v0.0.0-20200323222414-85ca7c5b95cd/unix/syscall_linux_test.go (about)

     1  // Copyright 2016 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 linux
     6  
     7  package unix_test
     8  
     9  import (
    10  	"bufio"
    11  	"bytes"
    12  	"errors"
    13  	"fmt"
    14  	"io/ioutil"
    15  	"os"
    16  	"runtime"
    17  	"runtime/debug"
    18  	"strconv"
    19  	"strings"
    20  	"testing"
    21  	"time"
    22  
    23  	"golang.org/x/sys/unix"
    24  )
    25  
    26  func TestIoctlGetInt(t *testing.T) {
    27  	f, err := os.Open("/dev/random")
    28  	if err != nil {
    29  		t.Fatalf("failed to open device: %v", err)
    30  	}
    31  	defer f.Close()
    32  
    33  	v, err := unix.IoctlGetInt(int(f.Fd()), unix.RNDGETENTCNT)
    34  	if err != nil {
    35  		t.Fatalf("failed to perform ioctl: %v", err)
    36  	}
    37  
    38  	t.Logf("%d bits of entropy available", v)
    39  }
    40  
    41  func TestIoctlRetInt(t *testing.T) {
    42  	f, err := os.Open("/proc/self/ns/mnt")
    43  	if err != nil {
    44  		t.Skipf("skipping test, %v", err)
    45  	}
    46  	defer f.Close()
    47  
    48  	v, err := unix.IoctlRetInt(int(f.Fd()), unix.NS_GET_NSTYPE)
    49  	if err != nil {
    50  		if err == unix.ENOTTY {
    51  			t.Skipf("old kernel? (need Linux >= 4.11)")
    52  		}
    53  		t.Fatalf("failed to perform ioctl: %v", err)
    54  	}
    55  	if v != unix.CLONE_NEWNS {
    56  		t.Fatalf("unexpected return from ioctl; expected %v, got %v", v, unix.CLONE_NEWNS)
    57  	}
    58  }
    59  
    60  func TestIoctlGetRTCTime(t *testing.T) {
    61  	f, err := os.Open("/dev/rtc0")
    62  	if err != nil {
    63  		t.Skipf("skipping test, %v", err)
    64  	}
    65  	defer f.Close()
    66  
    67  	v, err := unix.IoctlGetRTCTime(int(f.Fd()))
    68  	if err != nil {
    69  		t.Fatalf("failed to perform ioctl: %v", err)
    70  	}
    71  
    72  	t.Logf("RTC time: %04d-%02d-%02d %02d:%02d:%02d", v.Year+1900, v.Mon+1, v.Mday, v.Hour, v.Min, v.Sec)
    73  }
    74  
    75  func TestPpoll(t *testing.T) {
    76  	if runtime.GOOS == "android" {
    77  		t.Skip("mkfifo syscall is not available on android, skipping test")
    78  	}
    79  
    80  	defer chtmpdir(t)()
    81  	f, cleanup := mktmpfifo(t)
    82  	defer cleanup()
    83  
    84  	const timeout = 100 * time.Millisecond
    85  
    86  	ok := make(chan bool, 1)
    87  	go func() {
    88  		select {
    89  		case <-time.After(10 * timeout):
    90  			t.Errorf("Ppoll: failed to timeout after %d", 10*timeout)
    91  		case <-ok:
    92  		}
    93  	}()
    94  
    95  	fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}}
    96  	timeoutTs := unix.NsecToTimespec(int64(timeout))
    97  	n, err := unix.Ppoll(fds, &timeoutTs, nil)
    98  	ok <- true
    99  	if err != nil {
   100  		t.Errorf("Ppoll: unexpected error: %v", err)
   101  		return
   102  	}
   103  	if n != 0 {
   104  		t.Errorf("Ppoll: wrong number of events: got %v, expected %v", n, 0)
   105  		return
   106  	}
   107  }
   108  
   109  func TestTime(t *testing.T) {
   110  	var ut unix.Time_t
   111  	ut2, err := unix.Time(&ut)
   112  	if err != nil {
   113  		t.Fatalf("Time: %v", err)
   114  	}
   115  	if ut != ut2 {
   116  		t.Errorf("Time: return value %v should be equal to argument %v", ut2, ut)
   117  	}
   118  
   119  	var now time.Time
   120  
   121  	for i := 0; i < 10; i++ {
   122  		ut, err = unix.Time(nil)
   123  		if err != nil {
   124  			t.Fatalf("Time: %v", err)
   125  		}
   126  
   127  		now = time.Now()
   128  		diff := int64(ut) - now.Unix()
   129  		if -1 <= diff && diff <= 1 {
   130  			return
   131  		}
   132  	}
   133  
   134  	t.Errorf("Time: return value %v should be nearly equal to time.Now().Unix() %v±1", ut, now.Unix())
   135  }
   136  
   137  func TestUtime(t *testing.T) {
   138  	defer chtmpdir(t)()
   139  
   140  	touch(t, "file1")
   141  
   142  	buf := &unix.Utimbuf{
   143  		Modtime: 12345,
   144  	}
   145  
   146  	err := unix.Utime("file1", buf)
   147  	if err != nil {
   148  		t.Fatalf("Utime: %v", err)
   149  	}
   150  
   151  	fi, err := os.Stat("file1")
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	if fi.ModTime().Unix() != 12345 {
   157  		t.Errorf("Utime: failed to change modtime: expected %v, got %v", 12345, fi.ModTime().Unix())
   158  	}
   159  }
   160  
   161  func TestRlimitAs(t *testing.T) {
   162  	// disable GC during to avoid flaky test
   163  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   164  
   165  	var rlim unix.Rlimit
   166  	err := unix.Getrlimit(unix.RLIMIT_AS, &rlim)
   167  	if err != nil {
   168  		t.Fatalf("Getrlimit: %v", err)
   169  	}
   170  	var zero unix.Rlimit
   171  	if zero == rlim {
   172  		t.Fatalf("Getrlimit: got zero value %#v", rlim)
   173  	}
   174  	set := rlim
   175  	set.Cur = uint64(unix.Getpagesize())
   176  	err = unix.Setrlimit(unix.RLIMIT_AS, &set)
   177  	if err != nil {
   178  		t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
   179  	}
   180  
   181  	// RLIMIT_AS was set to the page size, so mmap()'ing twice the page size
   182  	// should fail. See 'man 2 getrlimit'.
   183  	_, err = unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
   184  	if err == nil {
   185  		t.Fatal("Mmap: unexpectedly succeeded after setting RLIMIT_AS")
   186  	}
   187  
   188  	err = unix.Setrlimit(unix.RLIMIT_AS, &rlim)
   189  	if err != nil {
   190  		t.Fatalf("Setrlimit: restore failed: %#v %v", rlim, err)
   191  	}
   192  
   193  	b, err := unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
   194  	if err != nil {
   195  		t.Fatalf("Mmap: %v", err)
   196  	}
   197  	err = unix.Munmap(b)
   198  	if err != nil {
   199  		t.Fatalf("Munmap: %v", err)
   200  	}
   201  }
   202  
   203  func TestPselect(t *testing.T) {
   204  	for {
   205  		n, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, nil)
   206  		if err == unix.EINTR {
   207  			t.Logf("Pselect interrupted")
   208  			continue
   209  		} else if err != nil {
   210  			t.Fatalf("Pselect: %v", err)
   211  		}
   212  		if n != 0 {
   213  			t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
   214  		}
   215  		break
   216  	}
   217  
   218  	dur := 2500 * time.Microsecond
   219  	ts := unix.NsecToTimespec(int64(dur))
   220  	var took time.Duration
   221  	for {
   222  		start := time.Now()
   223  		n, err := unix.Pselect(0, nil, nil, nil, &ts, nil)
   224  		took = time.Since(start)
   225  		if err == unix.EINTR {
   226  			t.Logf("Pselect interrupted after %v", took)
   227  			continue
   228  		} else if err != nil {
   229  			t.Fatalf("Pselect: %v", err)
   230  		}
   231  		if n != 0 {
   232  			t.Fatalf("Pselect: got %v ready file descriptors, expected 0", n)
   233  		}
   234  		break
   235  	}
   236  
   237  	if took < dur {
   238  		t.Errorf("Pselect: timeout should have been at least %v, got %v", dur, took)
   239  	}
   240  }
   241  
   242  func TestSchedSetaffinity(t *testing.T) {
   243  	var newMask unix.CPUSet
   244  	newMask.Zero()
   245  	if newMask.Count() != 0 {
   246  		t.Errorf("CpuZero: didn't zero CPU set: %v", newMask)
   247  	}
   248  	cpu := 1
   249  	newMask.Set(cpu)
   250  	if newMask.Count() != 1 || !newMask.IsSet(cpu) {
   251  		t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
   252  	}
   253  	cpu = 5
   254  	newMask.Set(cpu)
   255  	if newMask.Count() != 2 || !newMask.IsSet(cpu) {
   256  		t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
   257  	}
   258  	newMask.Clear(cpu)
   259  	if newMask.Count() != 1 || newMask.IsSet(cpu) {
   260  		t.Errorf("CpuClr: didn't clear CPU %d in set: %v", cpu, newMask)
   261  	}
   262  
   263  	runtime.LockOSThread()
   264  	defer runtime.UnlockOSThread()
   265  
   266  	var oldMask unix.CPUSet
   267  	err := unix.SchedGetaffinity(0, &oldMask)
   268  	if err != nil {
   269  		t.Fatalf("SchedGetaffinity: %v", err)
   270  	}
   271  
   272  	if runtime.NumCPU() < 2 {
   273  		t.Skip("skipping setaffinity tests on single CPU system")
   274  	}
   275  	if runtime.GOOS == "android" {
   276  		t.Skip("skipping setaffinity tests on android")
   277  	}
   278  
   279  	// On a system like ppc64x where some cores can be disabled using ppc64_cpu,
   280  	// setaffinity should only be called with enabled cores. The valid cores
   281  	// are found from the oldMask, but if none are found then the setaffinity
   282  	// tests are skipped. Issue #27875.
   283  	cpu = 1
   284  	if !oldMask.IsSet(cpu) {
   285  		newMask.Zero()
   286  		for i := 0; i < len(oldMask); i++ {
   287  			if oldMask.IsSet(i) {
   288  				newMask.Set(i)
   289  				break
   290  			}
   291  		}
   292  		if newMask.Count() == 0 {
   293  			t.Skip("skipping setaffinity tests if CPU not available")
   294  		}
   295  	}
   296  
   297  	err = unix.SchedSetaffinity(0, &newMask)
   298  	if err != nil {
   299  		t.Fatalf("SchedSetaffinity: %v", err)
   300  	}
   301  
   302  	var gotMask unix.CPUSet
   303  	err = unix.SchedGetaffinity(0, &gotMask)
   304  	if err != nil {
   305  		t.Fatalf("SchedGetaffinity: %v", err)
   306  	}
   307  
   308  	if gotMask != newMask {
   309  		t.Errorf("SchedSetaffinity: returned affinity mask does not match set affinity mask")
   310  	}
   311  
   312  	// Restore old mask so it doesn't affect successive tests
   313  	err = unix.SchedSetaffinity(0, &oldMask)
   314  	if err != nil {
   315  		t.Fatalf("SchedSetaffinity: %v", err)
   316  	}
   317  }
   318  
   319  func TestStatx(t *testing.T) {
   320  	var stx unix.Statx_t
   321  	err := unix.Statx(unix.AT_FDCWD, ".", 0, 0, &stx)
   322  	if err == unix.ENOSYS || err == unix.EPERM {
   323  		t.Skip("statx syscall is not available, skipping test")
   324  	} else if err != nil {
   325  		t.Fatalf("Statx: %v", err)
   326  	}
   327  
   328  	defer chtmpdir(t)()
   329  	touch(t, "file1")
   330  
   331  	var st unix.Stat_t
   332  	err = unix.Stat("file1", &st)
   333  	if err != nil {
   334  		t.Fatalf("Stat: %v", err)
   335  	}
   336  
   337  	flags := unix.AT_STATX_SYNC_AS_STAT
   338  	err = unix.Statx(unix.AT_FDCWD, "file1", flags, unix.STATX_ALL, &stx)
   339  	if err != nil {
   340  		t.Fatalf("Statx: %v", err)
   341  	}
   342  
   343  	if uint32(stx.Mode) != st.Mode {
   344  		t.Errorf("Statx: returned stat mode does not match Stat")
   345  	}
   346  
   347  	ctime := unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
   348  	mtime := unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
   349  
   350  	if stx.Ctime != ctime {
   351  		t.Errorf("Statx: returned stat ctime does not match Stat")
   352  	}
   353  	if stx.Mtime != mtime {
   354  		t.Errorf("Statx: returned stat mtime does not match Stat")
   355  	}
   356  
   357  	err = os.Symlink("file1", "symlink1")
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  
   362  	err = unix.Lstat("symlink1", &st)
   363  	if err != nil {
   364  		t.Fatalf("Lstat: %v", err)
   365  	}
   366  
   367  	err = unix.Statx(unix.AT_FDCWD, "symlink1", flags, unix.STATX_BASIC_STATS, &stx)
   368  	if err != nil {
   369  		t.Fatalf("Statx: %v", err)
   370  	}
   371  
   372  	// follow symlink, expect a regulat file
   373  	if stx.Mode&unix.S_IFREG == 0 {
   374  		t.Errorf("Statx: didn't follow symlink")
   375  	}
   376  
   377  	err = unix.Statx(unix.AT_FDCWD, "symlink1", flags|unix.AT_SYMLINK_NOFOLLOW, unix.STATX_ALL, &stx)
   378  	if err != nil {
   379  		t.Fatalf("Statx: %v", err)
   380  	}
   381  
   382  	// follow symlink, expect a symlink
   383  	if stx.Mode&unix.S_IFLNK == 0 {
   384  		t.Errorf("Statx: unexpectedly followed symlink")
   385  	}
   386  	if uint32(stx.Mode) != st.Mode {
   387  		t.Errorf("Statx: returned stat mode does not match Lstat")
   388  	}
   389  
   390  	ctime = unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
   391  	mtime = unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
   392  
   393  	if stx.Ctime != ctime {
   394  		t.Errorf("Statx: returned stat ctime does not match Lstat")
   395  	}
   396  	if stx.Mtime != mtime {
   397  		t.Errorf("Statx: returned stat mtime does not match Lstat")
   398  	}
   399  }
   400  
   401  // stringsFromByteSlice converts a sequence of attributes to a []string.
   402  // On Linux, each entry is a NULL-terminated string.
   403  func stringsFromByteSlice(buf []byte) []string {
   404  	var result []string
   405  	off := 0
   406  	for i, b := range buf {
   407  		if b == 0 {
   408  			result = append(result, string(buf[off:i]))
   409  			off = i + 1
   410  		}
   411  	}
   412  	return result
   413  }
   414  
   415  func TestFaccessat(t *testing.T) {
   416  	defer chtmpdir(t)()
   417  	touch(t, "file1")
   418  
   419  	err := unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 0)
   420  	if err != nil {
   421  		t.Errorf("Faccessat: unexpected error: %v", err)
   422  	}
   423  
   424  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 2)
   425  	if err != unix.EINVAL {
   426  		t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
   427  	}
   428  
   429  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_EACCESS)
   430  	if err != nil {
   431  		t.Errorf("Faccessat: unexpected error: %v", err)
   432  	}
   433  
   434  	err = os.Symlink("file1", "symlink1")
   435  	if err != nil {
   436  		t.Fatal(err)
   437  	}
   438  
   439  	err = unix.Faccessat(unix.AT_FDCWD, "symlink1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
   440  	if err != nil {
   441  		t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err)
   442  	}
   443  
   444  	// We can't really test AT_SYMLINK_NOFOLLOW, because there
   445  	// doesn't seem to be any way to change the mode of a symlink.
   446  	// We don't test AT_EACCESS because such tests are only
   447  	// meaningful if run as root.
   448  
   449  	err = unix.Fchmodat(unix.AT_FDCWD, "file1", 0, 0)
   450  	if err != nil {
   451  		t.Errorf("Fchmodat: unexpected error %v", err)
   452  	}
   453  
   454  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.F_OK, unix.AT_SYMLINK_NOFOLLOW)
   455  	if err != nil {
   456  		t.Errorf("Faccessat: unexpected error: %v", err)
   457  	}
   458  
   459  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
   460  	if err != unix.EACCES {
   461  		if unix.Getuid() != 0 {
   462  			t.Errorf("Faccessat: unexpected error: %v, want EACCES", err)
   463  		}
   464  	}
   465  }
   466  
   467  func TestSyncFileRange(t *testing.T) {
   468  	file, err := ioutil.TempFile("", "TestSyncFileRange")
   469  	if err != nil {
   470  		t.Fatal(err)
   471  	}
   472  	defer os.Remove(file.Name())
   473  	defer file.Close()
   474  
   475  	err = unix.SyncFileRange(int(file.Fd()), 0, 0, 0)
   476  	if err == unix.ENOSYS || err == unix.EPERM {
   477  		t.Skip("sync_file_range syscall is not available, skipping test")
   478  	} else if err != nil {
   479  		t.Fatalf("SyncFileRange: %v", err)
   480  	}
   481  
   482  	// invalid flags
   483  	flags := 0xf00
   484  	err = unix.SyncFileRange(int(file.Fd()), 0, 0, flags)
   485  	if err != unix.EINVAL {
   486  		t.Fatalf("SyncFileRange: unexpected error: %v, want EINVAL", err)
   487  	}
   488  }
   489  
   490  func TestClockNanosleep(t *testing.T) {
   491  	delay := 50 * time.Millisecond
   492  
   493  	// Relative timespec.
   494  	start := time.Now()
   495  	rel := unix.NsecToTimespec(delay.Nanoseconds())
   496  	remain := unix.Timespec{}
   497  	for {
   498  		err := unix.ClockNanosleep(unix.CLOCK_MONOTONIC, 0, &rel, &remain)
   499  		if err == unix.ENOSYS || err == unix.EPERM {
   500  			t.Skip("clock_nanosleep syscall is not available, skipping test")
   501  		} else if err == unix.EINTR {
   502  			t.Logf("ClockNanosleep interrupted after %v", time.Since(start))
   503  			rel = remain
   504  			continue
   505  		} else if err != nil {
   506  			t.Errorf("ClockNanosleep(CLOCK_MONOTONIC, 0, %#v, nil) = %v", &rel, err)
   507  		} else if slept := time.Since(start); slept < delay {
   508  			t.Errorf("ClockNanosleep(CLOCK_MONOTONIC, 0, %#v, nil) slept only %v", &rel, slept)
   509  		}
   510  		break
   511  	}
   512  
   513  	// Absolute timespec.
   514  	for {
   515  		start = time.Now()
   516  		until := start.Add(delay)
   517  		abs := unix.NsecToTimespec(until.UnixNano())
   518  		err := unix.ClockNanosleep(unix.CLOCK_REALTIME, unix.TIMER_ABSTIME, &abs, nil)
   519  		if err == unix.EINTR {
   520  			t.Logf("ClockNanosleep interrupted after %v", time.Since(start))
   521  			continue
   522  		} else if err != nil {
   523  			t.Errorf("ClockNanosleep(CLOCK_REALTIME, TIMER_ABSTIME, %#v (=%v), nil) = %v", &abs, until, err)
   524  		} else if slept := time.Since(start); slept < delay {
   525  			t.Errorf("ClockNanosleep(CLOCK_REALTIME, TIMER_ABSTIME, %#v (=%v), nil) slept only %v", &abs, until, slept)
   526  		}
   527  		break
   528  	}
   529  
   530  	// Invalid clock. clock_nanosleep(2) says EINVAL, but it’s actually EOPNOTSUPP.
   531  	err := unix.ClockNanosleep(unix.CLOCK_THREAD_CPUTIME_ID, 0, &rel, nil)
   532  	if err != unix.EINVAL && err != unix.EOPNOTSUPP {
   533  		t.Errorf("ClockNanosleep(CLOCK_THREAD_CPUTIME_ID, 0, %#v, nil) = %v, want EINVAL or EOPNOTSUPP", &rel, err)
   534  	}
   535  }
   536  
   537  func TestOpenByHandleAt(t *testing.T) {
   538  	skipIfNotSupported := func(t *testing.T, name string, err error) {
   539  		if err == unix.EPERM {
   540  			t.Skipf("skipping %s test without CAP_DAC_READ_SEARCH", name)
   541  		}
   542  		if err == unix.ENOSYS {
   543  			t.Skipf("%s system call not available", name)
   544  		}
   545  		if err == unix.EOPNOTSUPP {
   546  			t.Skipf("%s not supported on this filesystem", name)
   547  		}
   548  	}
   549  
   550  	h, mountID, err := unix.NameToHandleAt(unix.AT_FDCWD, "syscall_linux_test.go", 0)
   551  	if err != nil {
   552  		skipIfNotSupported(t, "name_to_handle_at", err)
   553  		t.Fatalf("NameToHandleAt: %v", err)
   554  	}
   555  	t.Logf("mountID: %v, handle: size=%d, type=%d, bytes=%q", mountID,
   556  		h.Size(), h.Type(), h.Bytes())
   557  	mount, err := openMountByID(mountID)
   558  	if err != nil {
   559  		t.Fatalf("openMountByID: %v", err)
   560  	}
   561  	defer mount.Close()
   562  
   563  	for _, clone := range []bool{false, true} {
   564  		t.Run("clone="+strconv.FormatBool(clone), func(t *testing.T) {
   565  			if clone {
   566  				h = unix.NewFileHandle(h.Type(), h.Bytes())
   567  			}
   568  			fd, err := unix.OpenByHandleAt(int(mount.Fd()), h, unix.O_RDONLY)
   569  			skipIfNotSupported(t, "open_by_handle_at", err)
   570  			if err != nil {
   571  				t.Fatalf("OpenByHandleAt: %v", err)
   572  			}
   573  			defer unix.Close(fd)
   574  
   575  			t.Logf("opened fd %v", fd)
   576  			f := os.NewFile(uintptr(fd), "")
   577  			slurp, err := ioutil.ReadAll(f)
   578  			if err != nil {
   579  				t.Fatal(err)
   580  			}
   581  			const substr = "Some substring for a test."
   582  			if !strings.Contains(string(slurp), substr) {
   583  				t.Errorf("didn't find substring %q in opened file; read %d bytes", substr, len(slurp))
   584  			}
   585  		})
   586  	}
   587  }
   588  
   589  func openMountByID(mountID int) (f *os.File, err error) {
   590  	mi, err := os.Open("/proc/self/mountinfo")
   591  	if err != nil {
   592  		return nil, err
   593  	}
   594  	defer mi.Close()
   595  	bs := bufio.NewScanner(mi)
   596  	wantPrefix := []byte(fmt.Sprintf("%v ", mountID))
   597  	for bs.Scan() {
   598  		if !bytes.HasPrefix(bs.Bytes(), wantPrefix) {
   599  			continue
   600  		}
   601  		fields := strings.Fields(bs.Text())
   602  		dev := fields[4]
   603  		return os.Open(dev)
   604  	}
   605  	if err := bs.Err(); err != nil {
   606  		return nil, err
   607  	}
   608  	return nil, errors.New("mountID not found")
   609  }
   610  
   611  func TestEpoll(t *testing.T) {
   612  	efd, err := unix.EpollCreate1(unix.EPOLL_CLOEXEC)
   613  	if err != nil {
   614  		t.Fatalf("EpollCreate1: %v", err)
   615  	}
   616  	defer unix.Close(efd)
   617  
   618  	r, w, err := os.Pipe()
   619  	if err != nil {
   620  		t.Fatal(err)
   621  	}
   622  	defer r.Close()
   623  	defer w.Close()
   624  
   625  	fd := int(r.Fd())
   626  	ev := unix.EpollEvent{Events: unix.EPOLLIN, Fd: int32(fd)}
   627  
   628  	err = unix.EpollCtl(efd, unix.EPOLL_CTL_ADD, fd, &ev)
   629  	if err != nil {
   630  		t.Fatalf("EpollCtl: %v", err)
   631  	}
   632  
   633  	if _, err := w.Write([]byte("HELLO GOPHER")); err != nil {
   634  		t.Fatal(err)
   635  	}
   636  
   637  	events := make([]unix.EpollEvent, 128)
   638  	n, err := unix.EpollWait(efd, events, 1)
   639  	if err != nil {
   640  		t.Fatalf("EpollWait: %v", err)
   641  	}
   642  
   643  	if n != 1 {
   644  		t.Errorf("EpollWait: wrong number of events: got %v, expected 1", n)
   645  	}
   646  
   647  	got := int(events[0].Fd)
   648  	if got != fd {
   649  		t.Errorf("EpollWait: wrong Fd in event: got %v, expected %v", got, fd)
   650  	}
   651  }
   652  
   653  func TestPrctlRetInt(t *testing.T) {
   654  	err := unix.Prctl(unix.PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
   655  	if err != nil {
   656  		t.Skipf("Prctl: %v, skipping test", err)
   657  	}
   658  	v, err := unix.PrctlRetInt(unix.PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)
   659  	if err != nil {
   660  		t.Fatalf("failed to perform prctl: %v", err)
   661  	}
   662  	if v != 1 {
   663  		t.Fatalf("unexpected return from prctl; got %v, expected %v", v, 1)
   664  	}
   665  }