github.com/fletavendor/sys@v0.0.0-20181107165924-66b7b1311ac8/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  	"io/ioutil"
    11  	"os"
    12  	"runtime"
    13  	"runtime/debug"
    14  	"testing"
    15  	"time"
    16  
    17  	"golang.org/x/sys/unix"
    18  )
    19  
    20  func TestIoctlGetInt(t *testing.T) {
    21  	f, err := os.Open("/dev/random")
    22  	if err != nil {
    23  		t.Fatalf("failed to open device: %v", err)
    24  	}
    25  	defer f.Close()
    26  
    27  	v, err := unix.IoctlGetInt(int(f.Fd()), unix.RNDGETENTCNT)
    28  	if err != nil {
    29  		t.Fatalf("failed to perform ioctl: %v", err)
    30  	}
    31  
    32  	t.Logf("%d bits of entropy available", v)
    33  }
    34  
    35  func TestPpoll(t *testing.T) {
    36  	if runtime.GOOS == "android" {
    37  		t.Skip("mkfifo syscall is not available on android, skipping test")
    38  	}
    39  
    40  	f, cleanup := mktmpfifo(t)
    41  	defer cleanup()
    42  
    43  	const timeout = 100 * time.Millisecond
    44  
    45  	ok := make(chan bool, 1)
    46  	go func() {
    47  		select {
    48  		case <-time.After(10 * timeout):
    49  			t.Errorf("Ppoll: failed to timeout after %d", 10*timeout)
    50  		case <-ok:
    51  		}
    52  	}()
    53  
    54  	fds := []unix.PollFd{{Fd: int32(f.Fd()), Events: unix.POLLIN}}
    55  	timeoutTs := unix.NsecToTimespec(int64(timeout))
    56  	n, err := unix.Ppoll(fds, &timeoutTs, nil)
    57  	ok <- true
    58  	if err != nil {
    59  		t.Errorf("Ppoll: unexpected error: %v", err)
    60  		return
    61  	}
    62  	if n != 0 {
    63  		t.Errorf("Ppoll: wrong number of events: got %v, expected %v", n, 0)
    64  		return
    65  	}
    66  }
    67  
    68  func TestTime(t *testing.T) {
    69  	var ut unix.Time_t
    70  	ut2, err := unix.Time(&ut)
    71  	if err != nil {
    72  		t.Fatalf("Time: %v", err)
    73  	}
    74  	if ut != ut2 {
    75  		t.Errorf("Time: return value %v should be equal to argument %v", ut2, ut)
    76  	}
    77  
    78  	var now time.Time
    79  
    80  	for i := 0; i < 10; i++ {
    81  		ut, err = unix.Time(nil)
    82  		if err != nil {
    83  			t.Fatalf("Time: %v", err)
    84  		}
    85  
    86  		now = time.Now()
    87  
    88  		if int64(ut) == now.Unix() {
    89  			return
    90  		}
    91  	}
    92  
    93  	t.Errorf("Time: return value %v should be nearly equal to time.Now().Unix() %v", ut, now.Unix())
    94  }
    95  
    96  func TestUtime(t *testing.T) {
    97  	defer chtmpdir(t)()
    98  
    99  	touch(t, "file1")
   100  
   101  	buf := &unix.Utimbuf{
   102  		Modtime: 12345,
   103  	}
   104  
   105  	err := unix.Utime("file1", buf)
   106  	if err != nil {
   107  		t.Fatalf("Utime: %v", err)
   108  	}
   109  
   110  	fi, err := os.Stat("file1")
   111  	if err != nil {
   112  		t.Fatal(err)
   113  	}
   114  
   115  	if fi.ModTime().Unix() != 12345 {
   116  		t.Errorf("Utime: failed to change modtime: expected %v, got %v", 12345, fi.ModTime().Unix())
   117  	}
   118  }
   119  
   120  func TestUtimesNanoAt(t *testing.T) {
   121  	defer chtmpdir(t)()
   122  
   123  	symlink := "symlink1"
   124  	os.Remove(symlink)
   125  	err := os.Symlink("nonexisting", symlink)
   126  	if err != nil {
   127  		t.Fatal(err)
   128  	}
   129  
   130  	ts := []unix.Timespec{
   131  		{Sec: 1111, Nsec: 2222},
   132  		{Sec: 3333, Nsec: 4444},
   133  	}
   134  	err = unix.UtimesNanoAt(unix.AT_FDCWD, symlink, ts, unix.AT_SYMLINK_NOFOLLOW)
   135  	if err != nil {
   136  		t.Fatalf("UtimesNanoAt: %v", err)
   137  	}
   138  
   139  	var st unix.Stat_t
   140  	err = unix.Lstat(symlink, &st)
   141  	if err != nil {
   142  		t.Fatalf("Lstat: %v", err)
   143  	}
   144  
   145  	// Only check Mtim, Atim might not be supported by the underlying filesystem
   146  	expected := ts[1]
   147  	if st.Mtim.Nsec == 0 {
   148  		// Some filesystems only support 1-second time stamp resolution
   149  		// and will always set Nsec to 0.
   150  		expected.Nsec = 0
   151  	}
   152  	if st.Mtim != expected {
   153  		t.Errorf("UtimesNanoAt: wrong mtime: expected %v, got %v", expected, st.Mtim)
   154  	}
   155  }
   156  
   157  func TestRlimitAs(t *testing.T) {
   158  	// disable GC during to avoid flaky test
   159  	defer debug.SetGCPercent(debug.SetGCPercent(-1))
   160  
   161  	var rlim unix.Rlimit
   162  	err := unix.Getrlimit(unix.RLIMIT_AS, &rlim)
   163  	if err != nil {
   164  		t.Fatalf("Getrlimit: %v", err)
   165  	}
   166  	var zero unix.Rlimit
   167  	if zero == rlim {
   168  		t.Fatalf("Getrlimit: got zero value %#v", rlim)
   169  	}
   170  	set := rlim
   171  	set.Cur = uint64(unix.Getpagesize())
   172  	err = unix.Setrlimit(unix.RLIMIT_AS, &set)
   173  	if err != nil {
   174  		t.Fatalf("Setrlimit: set failed: %#v %v", set, err)
   175  	}
   176  
   177  	// RLIMIT_AS was set to the page size, so mmap()'ing twice the page size
   178  	// should fail. See 'man 2 getrlimit'.
   179  	_, err = unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
   180  	if err == nil {
   181  		t.Fatal("Mmap: unexpectedly succeeded after setting RLIMIT_AS")
   182  	}
   183  
   184  	err = unix.Setrlimit(unix.RLIMIT_AS, &rlim)
   185  	if err != nil {
   186  		t.Fatalf("Setrlimit: restore failed: %#v %v", rlim, err)
   187  	}
   188  
   189  	b, err := unix.Mmap(-1, 0, 2*unix.Getpagesize(), unix.PROT_NONE, unix.MAP_ANON|unix.MAP_PRIVATE)
   190  	if err != nil {
   191  		t.Fatalf("Mmap: %v", err)
   192  	}
   193  	err = unix.Munmap(b)
   194  	if err != nil {
   195  		t.Fatalf("Munmap: %v", err)
   196  	}
   197  }
   198  
   199  func TestSelect(t *testing.T) {
   200  	_, err := unix.Select(0, nil, nil, nil, &unix.Timeval{Sec: 0, Usec: 0})
   201  	if err != nil {
   202  		t.Fatalf("Select: %v", err)
   203  	}
   204  
   205  	dur := 150 * time.Millisecond
   206  	tv := unix.NsecToTimeval(int64(dur))
   207  	start := time.Now()
   208  	_, err = unix.Select(0, nil, nil, nil, &tv)
   209  	took := time.Since(start)
   210  	if err != nil {
   211  		t.Fatalf("Select: %v", err)
   212  	}
   213  
   214  	if took < dur {
   215  		t.Errorf("Select: timeout should have been at least %v, got %v", dur, took)
   216  	}
   217  }
   218  
   219  func TestPselect(t *testing.T) {
   220  	_, err := unix.Pselect(0, nil, nil, nil, &unix.Timespec{Sec: 0, Nsec: 0}, nil)
   221  	if err != nil {
   222  		t.Fatalf("Pselect: %v", err)
   223  	}
   224  
   225  	dur := 2500 * time.Microsecond
   226  	ts := unix.NsecToTimespec(int64(dur))
   227  	start := time.Now()
   228  	_, err = unix.Pselect(0, nil, nil, nil, &ts, nil)
   229  	took := time.Since(start)
   230  	if err != nil {
   231  		t.Fatalf("Pselect: %v", err)
   232  	}
   233  
   234  	if took < dur {
   235  		t.Errorf("Pselect: timeout should have been at least %v, got %v", dur, took)
   236  	}
   237  }
   238  
   239  func TestSchedSetaffinity(t *testing.T) {
   240  	runtime.LockOSThread()
   241  	defer runtime.UnlockOSThread()
   242  
   243  	var oldMask unix.CPUSet
   244  	err := unix.SchedGetaffinity(0, &oldMask)
   245  	if err != nil {
   246  		t.Fatalf("SchedGetaffinity: %v", err)
   247  	}
   248  
   249  	var newMask unix.CPUSet
   250  	newMask.Zero()
   251  	if newMask.Count() != 0 {
   252  		t.Errorf("CpuZero: didn't zero CPU set: %v", newMask)
   253  	}
   254  	cpu := 1
   255  	newMask.Set(cpu)
   256  	if newMask.Count() != 1 || !newMask.IsSet(cpu) {
   257  		t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
   258  	}
   259  	cpu = 5
   260  	newMask.Set(cpu)
   261  	if newMask.Count() != 2 || !newMask.IsSet(cpu) {
   262  		t.Errorf("CpuSet: didn't set CPU %d in set: %v", cpu, newMask)
   263  	}
   264  	newMask.Clear(cpu)
   265  	if newMask.Count() != 1 || newMask.IsSet(cpu) {
   266  		t.Errorf("CpuClr: didn't clear CPU %d in set: %v", cpu, newMask)
   267  	}
   268  
   269  	if runtime.NumCPU() < 2 {
   270  		t.Skip("skipping setaffinity tests on single CPU system")
   271  	}
   272  	if runtime.GOOS == "android" {
   273  		t.Skip("skipping setaffinity tests on android")
   274  	}
   275  
   276  	// On a system like ppc64x where some cores can be disabled using ppc64_cpu,
   277  	// setaffinity should only be called with enabled cores. The valid cores
   278  	// are found from the oldMask, but if none are found then the setaffinity
   279  	// tests are skipped. Issue #27875.
   280  	if !oldMask.IsSet(cpu) {
   281  		newMask.Zero()
   282  		for i := 0; i < len(oldMask); i++ {
   283  			if oldMask.IsSet(i) {
   284  				newMask.Set(i)
   285  				break
   286  			}
   287  		}
   288  		if newMask.Count() == 0 {
   289  			t.Skip("skipping setaffinity tests if CPU not available")
   290  		}
   291  	}
   292  
   293  	err = unix.SchedSetaffinity(0, &newMask)
   294  	if err != nil {
   295  		t.Fatalf("SchedSetaffinity: %v", err)
   296  	}
   297  
   298  	var gotMask unix.CPUSet
   299  	err = unix.SchedGetaffinity(0, &gotMask)
   300  	if err != nil {
   301  		t.Fatalf("SchedGetaffinity: %v", err)
   302  	}
   303  
   304  	if gotMask != newMask {
   305  		t.Errorf("SchedSetaffinity: returned affinity mask does not match set affinity mask")
   306  	}
   307  
   308  	// Restore old mask so it doesn't affect successive tests
   309  	err = unix.SchedSetaffinity(0, &oldMask)
   310  	if err != nil {
   311  		t.Fatalf("SchedSetaffinity: %v", err)
   312  	}
   313  }
   314  
   315  func TestStatx(t *testing.T) {
   316  	var stx unix.Statx_t
   317  	err := unix.Statx(unix.AT_FDCWD, ".", 0, 0, &stx)
   318  	if err == unix.ENOSYS || err == unix.EPERM {
   319  		t.Skip("statx syscall is not available, skipping test")
   320  	} else if err != nil {
   321  		t.Fatalf("Statx: %v", err)
   322  	}
   323  
   324  	defer chtmpdir(t)()
   325  	touch(t, "file1")
   326  
   327  	var st unix.Stat_t
   328  	err = unix.Stat("file1", &st)
   329  	if err != nil {
   330  		t.Fatalf("Stat: %v", err)
   331  	}
   332  
   333  	flags := unix.AT_STATX_SYNC_AS_STAT
   334  	err = unix.Statx(unix.AT_FDCWD, "file1", flags, unix.STATX_ALL, &stx)
   335  	if err != nil {
   336  		t.Fatalf("Statx: %v", err)
   337  	}
   338  
   339  	if uint32(stx.Mode) != st.Mode {
   340  		t.Errorf("Statx: returned stat mode does not match Stat")
   341  	}
   342  
   343  	ctime := unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
   344  	mtime := unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
   345  
   346  	if stx.Ctime != ctime {
   347  		t.Errorf("Statx: returned stat ctime does not match Stat")
   348  	}
   349  	if stx.Mtime != mtime {
   350  		t.Errorf("Statx: returned stat mtime does not match Stat")
   351  	}
   352  
   353  	err = os.Symlink("file1", "symlink1")
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  
   358  	err = unix.Lstat("symlink1", &st)
   359  	if err != nil {
   360  		t.Fatalf("Lstat: %v", err)
   361  	}
   362  
   363  	err = unix.Statx(unix.AT_FDCWD, "symlink1", flags, unix.STATX_BASIC_STATS, &stx)
   364  	if err != nil {
   365  		t.Fatalf("Statx: %v", err)
   366  	}
   367  
   368  	// follow symlink, expect a regulat file
   369  	if stx.Mode&unix.S_IFREG == 0 {
   370  		t.Errorf("Statx: didn't follow symlink")
   371  	}
   372  
   373  	err = unix.Statx(unix.AT_FDCWD, "symlink1", flags|unix.AT_SYMLINK_NOFOLLOW, unix.STATX_ALL, &stx)
   374  	if err != nil {
   375  		t.Fatalf("Statx: %v", err)
   376  	}
   377  
   378  	// follow symlink, expect a symlink
   379  	if stx.Mode&unix.S_IFLNK == 0 {
   380  		t.Errorf("Statx: unexpectedly followed symlink")
   381  	}
   382  	if uint32(stx.Mode) != st.Mode {
   383  		t.Errorf("Statx: returned stat mode does not match Lstat")
   384  	}
   385  
   386  	ctime = unix.StatxTimestamp{Sec: int64(st.Ctim.Sec), Nsec: uint32(st.Ctim.Nsec)}
   387  	mtime = unix.StatxTimestamp{Sec: int64(st.Mtim.Sec), Nsec: uint32(st.Mtim.Nsec)}
   388  
   389  	if stx.Ctime != ctime {
   390  		t.Errorf("Statx: returned stat ctime does not match Lstat")
   391  	}
   392  	if stx.Mtime != mtime {
   393  		t.Errorf("Statx: returned stat mtime does not match Lstat")
   394  	}
   395  }
   396  
   397  // stringsFromByteSlice converts a sequence of attributes to a []string.
   398  // On Linux, each entry is a NULL-terminated string.
   399  func stringsFromByteSlice(buf []byte) []string {
   400  	var result []string
   401  	off := 0
   402  	for i, b := range buf {
   403  		if b == 0 {
   404  			result = append(result, string(buf[off:i]))
   405  			off = i + 1
   406  		}
   407  	}
   408  	return result
   409  }
   410  
   411  func TestFaccessat(t *testing.T) {
   412  	defer chtmpdir(t)()
   413  	touch(t, "file1")
   414  
   415  	err := unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 0)
   416  	if err != nil {
   417  		t.Errorf("Faccessat: unexpected error: %v", err)
   418  	}
   419  
   420  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, 2)
   421  	if err != unix.EINVAL {
   422  		t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
   423  	}
   424  
   425  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_EACCESS)
   426  	if err != nil {
   427  		t.Errorf("Faccessat: unexpected error: %v", err)
   428  	}
   429  
   430  	err = os.Symlink("file1", "symlink1")
   431  	if err != nil {
   432  		t.Fatal(err)
   433  	}
   434  
   435  	err = unix.Faccessat(unix.AT_FDCWD, "symlink1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
   436  	if err != nil {
   437  		t.Errorf("Faccessat SYMLINK_NOFOLLOW: unexpected error %v", err)
   438  	}
   439  
   440  	// We can't really test AT_SYMLINK_NOFOLLOW, because there
   441  	// doesn't seem to be any way to change the mode of a symlink.
   442  	// We don't test AT_EACCESS because such tests are only
   443  	// meaningful if run as root.
   444  
   445  	err = unix.Fchmodat(unix.AT_FDCWD, "file1", 0, 0)
   446  	if err != nil {
   447  		t.Errorf("Fchmodat: unexpected error %v", err)
   448  	}
   449  
   450  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.F_OK, unix.AT_SYMLINK_NOFOLLOW)
   451  	if err != nil {
   452  		t.Errorf("Faccessat: unexpected error: %v", err)
   453  	}
   454  
   455  	err = unix.Faccessat(unix.AT_FDCWD, "file1", unix.R_OK, unix.AT_SYMLINK_NOFOLLOW)
   456  	if err != unix.EACCES {
   457  		if unix.Getuid() != 0 {
   458  			t.Errorf("Faccessat: unexpected error: %v, want EACCES", err)
   459  		}
   460  	}
   461  }
   462  
   463  func TestSyncFileRange(t *testing.T) {
   464  	file, err := ioutil.TempFile("", "TestSyncFileRange")
   465  	if err != nil {
   466  		t.Fatal(err)
   467  	}
   468  	defer os.Remove(file.Name())
   469  	defer file.Close()
   470  
   471  	err = unix.SyncFileRange(int(file.Fd()), 0, 0, 0)
   472  	if err == unix.ENOSYS || err == unix.EPERM {
   473  		t.Skip("sync_file_range syscall is not available, skipping test")
   474  	} else if err != nil {
   475  		t.Fatalf("SyncFileRange: %v", err)
   476  	}
   477  
   478  	// invalid flags
   479  	flags := 0xf00
   480  	err = unix.SyncFileRange(int(file.Fd()), 0, 0, flags)
   481  	if err != unix.EINVAL {
   482  		t.Fatalf("SyncFileRange: unexpected error: %v, want EINVAL", err)
   483  	}
   484  }