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