• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use libc::{_exit, mode_t, off_t};
2 use nix::errno::Errno;
3 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
4 use nix::fcntl::readlink;
5 use nix::fcntl::OFlag;
6 #[cfg(not(target_os = "redox"))]
7 use nix::fcntl::{self, open};
8 #[cfg(not(any(
9     target_os = "redox",
10     target_os = "fuchsia",
11     target_os = "haiku"
12 )))]
13 use nix::pty::{grantpt, posix_openpt, ptsname, unlockpt};
14 #[cfg(not(target_os = "redox"))]
15 use nix::sys::signal::{
16     sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal,
17 };
18 use nix::sys::stat::{self, Mode, SFlag};
19 use nix::sys::wait::*;
20 use nix::unistd::ForkResult::*;
21 use nix::unistd::*;
22 use std::env;
23 #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
24 use std::ffi::CString;
25 #[cfg(not(target_os = "redox"))]
26 use std::fs::DirBuilder;
27 use std::fs::{self, File};
28 use std::io::Write;
29 use std::os::unix::prelude::*;
30 #[cfg(not(any(
31     target_os = "fuchsia",
32     target_os = "redox",
33     target_os = "haiku"
34 )))]
35 use std::path::Path;
36 use tempfile::{tempdir, tempfile};
37 
38 use crate::*;
39 
40 #[test]
41 #[cfg(not(any(target_os = "netbsd")))]
test_fork_and_waitpid()42 fn test_fork_and_waitpid() {
43     let _m = crate::FORK_MTX.lock();
44 
45     // Safe: Child only calls `_exit`, which is signal-safe
46     match unsafe { fork() }.expect("Error: Fork Failed") {
47         Child => unsafe { _exit(0) },
48         Parent { child } => {
49             // assert that child was created and pid > 0
50             let child_raw: ::libc::pid_t = child.into();
51             assert!(child_raw > 0);
52             let wait_status = waitpid(child, None);
53             match wait_status {
54                 // assert that waitpid returned correct status and the pid is the one of the child
55                 Ok(WaitStatus::Exited(pid_t, _)) => assert_eq!(pid_t, child),
56 
57                 // panic, must never happen
58                 s @ Ok(_) => {
59                     panic!("Child exited {:?}, should never happen", s)
60                 }
61 
62                 // panic, waitpid should never fail
63                 Err(s) => panic!("Error: waitpid returned Err({:?}", s),
64             }
65         }
66     }
67 }
68 
69 #[test]
test_wait()70 fn test_wait() {
71     // Grab FORK_MTX so wait doesn't reap a different test's child process
72     let _m = crate::FORK_MTX.lock();
73 
74     // Safe: Child only calls `_exit`, which is signal-safe
75     match unsafe { fork() }.expect("Error: Fork Failed") {
76         Child => unsafe { _exit(0) },
77         Parent { child } => {
78             let wait_status = wait();
79 
80             // just assert that (any) one child returns with WaitStatus::Exited
81             assert_eq!(wait_status, Ok(WaitStatus::Exited(child, 0)));
82         }
83     }
84 }
85 
86 #[test]
test_mkstemp()87 fn test_mkstemp() {
88     let mut path = env::temp_dir();
89     path.push("nix_tempfile.XXXXXX");
90 
91     let result = mkstemp(&path);
92     match result {
93         Ok((fd, path)) => {
94             close(fd).unwrap();
95             unlink(path.as_path()).unwrap();
96         }
97         Err(e) => panic!("mkstemp failed: {}", e),
98     }
99 }
100 
101 #[test]
test_mkstemp_directory()102 fn test_mkstemp_directory() {
103     // mkstemp should fail if a directory is given
104     mkstemp(&env::temp_dir()).expect_err("assertion failed");
105 }
106 
107 #[test]
108 #[cfg(not(target_os = "redox"))]
test_mkfifo()109 fn test_mkfifo() {
110     let tempdir = tempdir().unwrap();
111     let mkfifo_fifo = tempdir.path().join("mkfifo_fifo");
112 
113     mkfifo(&mkfifo_fifo, Mode::S_IRUSR).unwrap();
114 
115     let stats = stat::stat(&mkfifo_fifo).unwrap();
116     let typ = stat::SFlag::from_bits_truncate(stats.st_mode as mode_t);
117     assert_eq!(typ, SFlag::S_IFIFO);
118 }
119 
120 #[test]
121 #[cfg(not(target_os = "redox"))]
test_mkfifo_directory()122 fn test_mkfifo_directory() {
123     // mkfifo should fail if a directory is given
124     mkfifo(&env::temp_dir(), Mode::S_IRUSR).expect_err("assertion failed");
125 }
126 
127 #[test]
128 #[cfg(not(any(
129     target_os = "macos",
130     target_os = "ios",
131     target_os = "android",
132     target_os = "redox",
133     target_os = "haiku"
134 )))]
test_mkfifoat_none()135 fn test_mkfifoat_none() {
136     let _m = crate::CWD_LOCK.read();
137 
138     let tempdir = tempdir().unwrap();
139     let mkfifoat_fifo = tempdir.path().join("mkfifoat_fifo");
140 
141     mkfifoat(None, &mkfifoat_fifo, Mode::S_IRUSR).unwrap();
142 
143     let stats = stat::stat(&mkfifoat_fifo).unwrap();
144     let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
145     assert_eq!(typ, SFlag::S_IFIFO);
146 }
147 
148 #[test]
149 #[cfg(not(any(
150     target_os = "macos",
151     target_os = "ios",
152     target_os = "android",
153     target_os = "redox",
154     target_os = "haiku"
155 )))]
test_mkfifoat()156 fn test_mkfifoat() {
157     use nix::fcntl;
158 
159     let tempdir = tempdir().unwrap();
160     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
161     let mkfifoat_name = "mkfifoat_name";
162 
163     mkfifoat(Some(dirfd), mkfifoat_name, Mode::S_IRUSR).unwrap();
164 
165     let stats =
166         stat::fstatat(dirfd, mkfifoat_name, fcntl::AtFlags::empty()).unwrap();
167     let typ = stat::SFlag::from_bits_truncate(stats.st_mode);
168     assert_eq!(typ, SFlag::S_IFIFO);
169 }
170 
171 #[test]
172 #[cfg(not(any(
173     target_os = "macos",
174     target_os = "ios",
175     target_os = "android",
176     target_os = "redox",
177     target_os = "haiku"
178 )))]
test_mkfifoat_directory_none()179 fn test_mkfifoat_directory_none() {
180     let _m = crate::CWD_LOCK.read();
181 
182     // mkfifoat should fail if a directory is given
183     mkfifoat(None, &env::temp_dir(), Mode::S_IRUSR)
184         .expect_err("assertion failed");
185 }
186 
187 #[test]
188 #[cfg(not(any(
189     target_os = "macos",
190     target_os = "ios",
191     target_os = "android",
192     target_os = "redox",
193     target_os = "haiku"
194 )))]
test_mkfifoat_directory()195 fn test_mkfifoat_directory() {
196     // mkfifoat should fail if a directory is given
197     let tempdir = tempdir().unwrap();
198     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
199     let mkfifoat_dir = "mkfifoat_dir";
200     stat::mkdirat(dirfd, mkfifoat_dir, Mode::S_IRUSR).unwrap();
201 
202     mkfifoat(Some(dirfd), mkfifoat_dir, Mode::S_IRUSR)
203         .expect_err("assertion failed");
204 }
205 
206 #[test]
test_getpid()207 fn test_getpid() {
208     let pid: ::libc::pid_t = getpid().into();
209     let ppid: ::libc::pid_t = getppid().into();
210     assert!(pid > 0);
211     assert!(ppid > 0);
212 }
213 
214 #[test]
215 #[cfg(not(target_os = "redox"))]
test_getsid()216 fn test_getsid() {
217     let none_sid: ::libc::pid_t = getsid(None).unwrap().into();
218     let pid_sid: ::libc::pid_t = getsid(Some(getpid())).unwrap().into();
219     assert!(none_sid > 0);
220     assert_eq!(none_sid, pid_sid);
221 }
222 
223 #[cfg(any(target_os = "linux", target_os = "android"))]
224 mod linux_android {
225     use nix::unistd::gettid;
226 
227     #[test]
test_gettid()228     fn test_gettid() {
229         let tid: ::libc::pid_t = gettid().into();
230         assert!(tid > 0);
231     }
232 }
233 
234 #[test]
235 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
236 #[cfg(not(any(
237     target_os = "ios",
238     target_os = "macos",
239     target_os = "redox",
240     target_os = "fuchsia",
241     target_os = "haiku"
242 )))]
test_setgroups()243 fn test_setgroups() {
244     // Skip this test when not run as root as `setgroups()` requires root.
245     skip_if_not_root!("test_setgroups");
246 
247     let _m = crate::GROUPS_MTX.lock();
248 
249     // Save the existing groups
250     let old_groups = getgroups().unwrap();
251 
252     // Set some new made up groups
253     let groups = [Gid::from_raw(123), Gid::from_raw(456)];
254     setgroups(&groups).unwrap();
255 
256     let new_groups = getgroups().unwrap();
257     assert_eq!(new_groups, groups);
258 
259     // Revert back to the old groups
260     setgroups(&old_groups).unwrap();
261 }
262 
263 #[test]
264 // `getgroups()` and `setgroups()` do not behave as expected on Apple platforms
265 #[cfg(not(any(
266     target_os = "ios",
267     target_os = "macos",
268     target_os = "redox",
269     target_os = "fuchsia",
270     target_os = "haiku",
271     target_os = "illumos"
272 )))]
test_initgroups()273 fn test_initgroups() {
274     // Skip this test when not run as root as `initgroups()` and `setgroups()`
275     // require root.
276     skip_if_not_root!("test_initgroups");
277 
278     let _m = crate::GROUPS_MTX.lock();
279 
280     // Save the existing groups
281     let old_groups = getgroups().unwrap();
282 
283     // It doesn't matter if the root user is not called "root" or if a user
284     // called "root" doesn't exist. We are just checking that the extra,
285     // made-up group, `123`, is set.
286     // FIXME: Test the other half of initgroups' functionality: whether the
287     // groups that the user belongs to are also set.
288     let user = CString::new("root").unwrap();
289     let group = Gid::from_raw(123);
290     let group_list = getgrouplist(&user, group).unwrap();
291     assert!(group_list.contains(&group));
292 
293     initgroups(&user, group).unwrap();
294 
295     let new_groups = getgroups().unwrap();
296     assert_eq!(new_groups, group_list);
297 
298     // Revert back to the old groups
299     setgroups(&old_groups).unwrap();
300 }
301 
302 #[cfg(not(any(target_os = "fuchsia", target_os = "redox")))]
303 macro_rules! execve_test_factory (
304     ($test_name:ident, $syscall:ident, $exe: expr $(, $pathname:expr, $flags:expr)*) => (
305 
306     #[cfg(test)]
307     mod $test_name {
308     use std::ffi::CStr;
309     use super::*;
310 
311     const EMPTY: &'static [u8] = b"\0";
312     const DASH_C: &'static [u8] = b"-c\0";
313     const BIGARG: &'static [u8] = b"echo nix!!! && echo foo=$foo && echo baz=$baz\0";
314     const FOO: &'static [u8] = b"foo=bar\0";
315     const BAZ: &'static [u8] = b"baz=quux\0";
316 
317     fn syscall_cstr_ref() -> Result<std::convert::Infallible, nix::Error> {
318         $syscall(
319             $exe,
320             $(CString::new($pathname).unwrap().as_c_str(), )*
321             &[CStr::from_bytes_with_nul(EMPTY).unwrap(),
322               CStr::from_bytes_with_nul(DASH_C).unwrap(),
323               CStr::from_bytes_with_nul(BIGARG).unwrap()],
324             &[CStr::from_bytes_with_nul(FOO).unwrap(),
325               CStr::from_bytes_with_nul(BAZ).unwrap()]
326             $(, $flags)*)
327     }
328 
329     fn syscall_cstring() -> Result<std::convert::Infallible, nix::Error> {
330         $syscall(
331             $exe,
332             $(CString::new($pathname).unwrap().as_c_str(), )*
333             &[CString::from(CStr::from_bytes_with_nul(EMPTY).unwrap()),
334               CString::from(CStr::from_bytes_with_nul(DASH_C).unwrap()),
335               CString::from(CStr::from_bytes_with_nul(BIGARG).unwrap())],
336             &[CString::from(CStr::from_bytes_with_nul(FOO).unwrap()),
337               CString::from(CStr::from_bytes_with_nul(BAZ).unwrap())]
338             $(, $flags)*)
339     }
340 
341     fn common_test(syscall: fn() -> Result<std::convert::Infallible, nix::Error>) {
342         if "execveat" == stringify!($syscall) {
343             // Though undocumented, Docker's default seccomp profile seems to
344             // block this syscall.  https://github.com/nix-rust/nix/issues/1122
345             skip_if_seccomp!($test_name);
346         }
347 
348         let m = crate::FORK_MTX.lock();
349         // The `exec`d process will write to `writer`, and we'll read that
350         // data from `reader`.
351         let (reader, writer) = pipe().unwrap();
352 
353         // Safe: Child calls `exit`, `dup`, `close` and the provided `exec*` family function.
354         // NOTE: Technically, this makes the macro unsafe to use because you could pass anything.
355         //       The tests make sure not to do that, though.
356         match unsafe{fork()}.unwrap() {
357             Child => {
358                 // Make `writer` be the stdout of the new process.
359                 dup2(writer, 1).unwrap();
360                 let r = syscall();
361                 let _ = std::io::stderr()
362                     .write_all(format!("{:?}", r).as_bytes());
363                 // Should only get here in event of error
364                 unsafe{ _exit(1) };
365             },
366             Parent { child } => {
367                 // Wait for the child to exit.
368                 let ws = waitpid(child, None);
369                 drop(m);
370                 assert_eq!(ws, Ok(WaitStatus::Exited(child, 0)));
371                 // Read 1024 bytes.
372                 let mut buf = [0u8; 1024];
373                 read(reader, &mut buf).unwrap();
374                 // It should contain the things we printed using `/bin/sh`.
375                 let string = String::from_utf8_lossy(&buf);
376                 assert!(string.contains("nix!!!"));
377                 assert!(string.contains("foo=bar"));
378                 assert!(string.contains("baz=quux"));
379             }
380         }
381     }
382 
383     // These tests frequently fail on musl, probably due to
384         // https://github.com/nix-rust/nix/issues/555
385     #[cfg_attr(target_env = "musl", ignore)]
386     #[test]
387     fn test_cstr_ref() {
388         common_test(syscall_cstr_ref);
389     }
390 
391     // These tests frequently fail on musl, probably due to
392         // https://github.com/nix-rust/nix/issues/555
393     #[cfg_attr(target_env = "musl", ignore)]
394     #[test]
395     fn test_cstring() {
396         common_test(syscall_cstring);
397     }
398     }
399 
400     )
401 );
402 
403 cfg_if! {
404     if #[cfg(target_os = "android")] {
405         execve_test_factory!(test_execve, execve, CString::new("/system/bin/sh").unwrap().as_c_str());
406         execve_test_factory!(test_fexecve, fexecve, File::open("/system/bin/sh").unwrap().into_raw_fd());
407     } else if #[cfg(any(target_os = "dragonfly",
408                         target_os = "freebsd",
409                         target_os = "linux"))] {
410         // These tests frequently fail on musl, probably due to
411         // https://github.com/nix-rust/nix/issues/555
412         execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
413         execve_test_factory!(test_fexecve, fexecve, File::open("/bin/sh").unwrap().into_raw_fd());
414     } else if #[cfg(any(target_os = "illumos",
415                         target_os = "ios",
416                         target_os = "macos",
417                         target_os = "netbsd",
418                         target_os = "openbsd",
419                         target_os = "solaris"))] {
420         execve_test_factory!(test_execve, execve, CString::new("/bin/sh").unwrap().as_c_str());
421         // No fexecve() on ios, macos, NetBSD, OpenBSD.
422     }
423 }
424 
425 #[cfg(any(target_os = "haiku", target_os = "linux", target_os = "openbsd"))]
426 execve_test_factory!(test_execvpe, execvpe, &CString::new("sh").unwrap());
427 
428 cfg_if! {
429     if #[cfg(target_os = "android")] {
430         use nix::fcntl::AtFlags;
431         execve_test_factory!(test_execveat_empty, execveat,
432                              File::open("/system/bin/sh").unwrap().into_raw_fd(),
433                              "", AtFlags::AT_EMPTY_PATH);
434         execve_test_factory!(test_execveat_relative, execveat,
435                              File::open("/system/bin/").unwrap().into_raw_fd(),
436                              "./sh", AtFlags::empty());
437         execve_test_factory!(test_execveat_absolute, execveat,
438                              File::open("/").unwrap().into_raw_fd(),
439                              "/system/bin/sh", AtFlags::empty());
440     } else if #[cfg(all(target_os = "linux", any(target_arch ="x86_64", target_arch ="x86")))] {
441         use nix::fcntl::AtFlags;
442         execve_test_factory!(test_execveat_empty, execveat, File::open("/bin/sh").unwrap().into_raw_fd(),
443                              "", AtFlags::AT_EMPTY_PATH);
444         execve_test_factory!(test_execveat_relative, execveat, File::open("/bin/").unwrap().into_raw_fd(),
445                              "./sh", AtFlags::empty());
446         execve_test_factory!(test_execveat_absolute, execveat, File::open("/").unwrap().into_raw_fd(),
447                              "/bin/sh", AtFlags::empty());
448     }
449 }
450 
451 #[test]
452 #[cfg(not(target_os = "fuchsia"))]
test_fchdir()453 fn test_fchdir() {
454     // fchdir changes the process's cwd
455     let _dr = crate::DirRestore::new();
456 
457     let tmpdir = tempdir().unwrap();
458     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
459     let tmpdir_fd = File::open(&tmpdir_path).unwrap().into_raw_fd();
460 
461     fchdir(tmpdir_fd).expect("assertion failed");
462     assert_eq!(getcwd().unwrap(), tmpdir_path);
463 
464     close(tmpdir_fd).expect("assertion failed");
465 }
466 
467 #[test]
test_getcwd()468 fn test_getcwd() {
469     // chdir changes the process's cwd
470     let _dr = crate::DirRestore::new();
471 
472     let tmpdir = tempdir().unwrap();
473     let tmpdir_path = tmpdir.path().canonicalize().unwrap();
474     chdir(&tmpdir_path).expect("assertion failed");
475     assert_eq!(getcwd().unwrap(), tmpdir_path);
476 
477     // make path 500 chars longer so that buffer doubling in getcwd
478     // kicks in.  Note: One path cannot be longer than 255 bytes
479     // (NAME_MAX) whole path cannot be longer than PATH_MAX (usually
480     // 4096 on linux, 1024 on macos)
481     let mut inner_tmp_dir = tmpdir_path;
482     for _ in 0..5 {
483         let newdir = "a".repeat(100);
484         inner_tmp_dir.push(newdir);
485         mkdir(inner_tmp_dir.as_path(), Mode::S_IRWXU)
486             .expect("assertion failed");
487     }
488     chdir(inner_tmp_dir.as_path()).expect("assertion failed");
489     assert_eq!(getcwd().unwrap(), inner_tmp_dir.as_path());
490 }
491 
492 #[test]
test_chown()493 fn test_chown() {
494     // Testing for anything other than our own UID/GID is hard.
495     let uid = Some(getuid());
496     let gid = Some(getgid());
497 
498     let tempdir = tempdir().unwrap();
499     let path = tempdir.path().join("file");
500     {
501         File::create(&path).unwrap();
502     }
503 
504     chown(&path, uid, gid).unwrap();
505     chown(&path, uid, None).unwrap();
506     chown(&path, None, gid).unwrap();
507 
508     fs::remove_file(&path).unwrap();
509     chown(&path, uid, gid).unwrap_err();
510 }
511 
512 #[test]
test_fchown()513 fn test_fchown() {
514     // Testing for anything other than our own UID/GID is hard.
515     let uid = Some(getuid());
516     let gid = Some(getgid());
517 
518     let path = tempfile().unwrap();
519     let fd = path.as_raw_fd();
520 
521     fchown(fd, uid, gid).unwrap();
522     fchown(fd, uid, None).unwrap();
523     fchown(fd, None, gid).unwrap();
524     fchown(999999999, uid, gid).unwrap_err();
525 }
526 
527 #[test]
528 #[cfg(not(target_os = "redox"))]
test_fchownat()529 fn test_fchownat() {
530     let _dr = crate::DirRestore::new();
531     // Testing for anything other than our own UID/GID is hard.
532     let uid = Some(getuid());
533     let gid = Some(getgid());
534 
535     let tempdir = tempdir().unwrap();
536     let path = tempdir.path().join("file");
537     {
538         File::create(&path).unwrap();
539     }
540 
541     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
542 
543     fchownat(Some(dirfd), "file", uid, gid, FchownatFlags::FollowSymlink)
544         .unwrap();
545 
546     chdir(tempdir.path()).unwrap();
547     fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap();
548 
549     fs::remove_file(&path).unwrap();
550     fchownat(None, "file", uid, gid, FchownatFlags::FollowSymlink).unwrap_err();
551 }
552 
553 #[test]
test_lseek()554 fn test_lseek() {
555     const CONTENTS: &[u8] = b"abcdef123456";
556     let mut tmp = tempfile().unwrap();
557     tmp.write_all(CONTENTS).unwrap();
558     let tmpfd = tmp.into_raw_fd();
559 
560     let offset: off_t = 5;
561     lseek(tmpfd, offset, Whence::SeekSet).unwrap();
562 
563     let mut buf = [0u8; 7];
564     crate::read_exact(tmpfd, &mut buf);
565     assert_eq!(b"f123456", &buf);
566 
567     close(tmpfd).unwrap();
568 }
569 
570 #[cfg(any(target_os = "linux", target_os = "android"))]
571 #[test]
test_lseek64()572 fn test_lseek64() {
573     const CONTENTS: &[u8] = b"abcdef123456";
574     let mut tmp = tempfile().unwrap();
575     tmp.write_all(CONTENTS).unwrap();
576     let tmpfd = tmp.into_raw_fd();
577 
578     lseek64(tmpfd, 5, Whence::SeekSet).unwrap();
579 
580     let mut buf = [0u8; 7];
581     crate::read_exact(tmpfd, &mut buf);
582     assert_eq!(b"f123456", &buf);
583 
584     close(tmpfd).unwrap();
585 }
586 
587 cfg_if! {
588     if #[cfg(any(target_os = "android", target_os = "linux"))] {
589         macro_rules! require_acct{
590             () => {
591                 require_capability!("test_acct", CAP_SYS_PACCT);
592             }
593         }
594     } else if #[cfg(target_os = "freebsd")] {
595         macro_rules! require_acct{
596             () => {
597                 skip_if_not_root!("test_acct");
598                 skip_if_jailed!("test_acct");
599             }
600         }
601     } else if #[cfg(not(any(target_os = "redox", target_os = "fuchsia", target_os = "haiku")))] {
602         macro_rules! require_acct{
603             () => {
604                 skip_if_not_root!("test_acct");
605             }
606         }
607     }
608 }
609 
610 #[test]
611 #[cfg(not(any(
612     target_os = "redox",
613     target_os = "fuchsia",
614     target_os = "haiku"
615 )))]
test_acct()616 fn test_acct() {
617     use std::process::Command;
618     use std::{thread, time};
619     use tempfile::NamedTempFile;
620 
621     let _m = crate::FORK_MTX.lock();
622     require_acct!();
623 
624     let file = NamedTempFile::new().unwrap();
625     let path = file.path().to_str().unwrap();
626 
627     acct::enable(path).unwrap();
628 
629     loop {
630         Command::new("echo").arg("Hello world").output().unwrap();
631         let len = fs::metadata(path).unwrap().len();
632         if len > 0 {
633             break;
634         }
635         thread::sleep(time::Duration::from_millis(10));
636     }
637     acct::disable().unwrap();
638 }
639 
640 #[test]
test_fpathconf_limited()641 fn test_fpathconf_limited() {
642     let f = tempfile().unwrap();
643     // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
644     let path_max = fpathconf(f.as_raw_fd(), PathconfVar::PATH_MAX);
645     assert!(
646         path_max
647             .expect("fpathconf failed")
648             .expect("PATH_MAX is unlimited")
649             > 0
650     );
651 }
652 
653 #[test]
test_pathconf_limited()654 fn test_pathconf_limited() {
655     // AFAIK, PATH_MAX is limited on all platforms, so it makes a good test
656     let path_max = pathconf("/", PathconfVar::PATH_MAX);
657     assert!(
658         path_max
659             .expect("pathconf failed")
660             .expect("PATH_MAX is unlimited")
661             > 0
662     );
663 }
664 
665 #[test]
test_sysconf_limited()666 fn test_sysconf_limited() {
667     // AFAIK, OPEN_MAX is limited on all platforms, so it makes a good test
668     let open_max = sysconf(SysconfVar::OPEN_MAX);
669     assert!(
670         open_max
671             .expect("sysconf failed")
672             .expect("OPEN_MAX is unlimited")
673             > 0
674     );
675 }
676 
677 #[cfg(target_os = "freebsd")]
678 #[test]
test_sysconf_unsupported()679 fn test_sysconf_unsupported() {
680     // I know of no sysconf variables that are unsupported everywhere, but
681     // _XOPEN_CRYPT is unsupported on FreeBSD 11.0, which is one of the platforms
682     // we test.
683     let open_max = sysconf(SysconfVar::_XOPEN_CRYPT);
684     assert!(open_max.expect("sysconf failed").is_none())
685 }
686 
687 #[cfg(any(
688     target_os = "android",
689     target_os = "dragonfly",
690     target_os = "freebsd",
691     target_os = "linux",
692     target_os = "openbsd"
693 ))]
694 #[test]
test_getresuid()695 fn test_getresuid() {
696     let resuids = getresuid().unwrap();
697     assert_ne!(resuids.real.as_raw(), libc::uid_t::MAX);
698     assert_ne!(resuids.effective.as_raw(), libc::uid_t::MAX);
699     assert_ne!(resuids.saved.as_raw(), libc::uid_t::MAX);
700 }
701 
702 #[cfg(any(
703     target_os = "android",
704     target_os = "dragonfly",
705     target_os = "freebsd",
706     target_os = "linux",
707     target_os = "openbsd"
708 ))]
709 #[test]
test_getresgid()710 fn test_getresgid() {
711     let resgids = getresgid().unwrap();
712     assert_ne!(resgids.real.as_raw(), libc::gid_t::MAX);
713     assert_ne!(resgids.effective.as_raw(), libc::gid_t::MAX);
714     assert_ne!(resgids.saved.as_raw(), libc::gid_t::MAX);
715 }
716 
717 // Test that we can create a pair of pipes.  No need to verify that they pass
718 // data; that's the domain of the OS, not nix.
719 #[test]
test_pipe()720 fn test_pipe() {
721     let (fd0, fd1) = pipe().unwrap();
722     let m0 = stat::SFlag::from_bits_truncate(
723         stat::fstat(fd0).unwrap().st_mode as mode_t,
724     );
725     // S_IFIFO means it's a pipe
726     assert_eq!(m0, SFlag::S_IFIFO);
727     let m1 = stat::SFlag::from_bits_truncate(
728         stat::fstat(fd1).unwrap().st_mode as mode_t,
729     );
730     assert_eq!(m1, SFlag::S_IFIFO);
731 }
732 
733 // pipe2(2) is the same as pipe(2), except it allows setting some flags.  Check
734 // that we can set a flag.
735 #[cfg(any(
736     target_os = "android",
737     target_os = "dragonfly",
738     target_os = "emscripten",
739     target_os = "freebsd",
740     target_os = "illumos",
741     target_os = "linux",
742     target_os = "netbsd",
743     target_os = "openbsd",
744     target_os = "redox",
745     target_os = "solaris"
746 ))]
747 #[test]
test_pipe2()748 fn test_pipe2() {
749     use nix::fcntl::{fcntl, FcntlArg, FdFlag};
750 
751     let (fd0, fd1) = pipe2(OFlag::O_CLOEXEC).unwrap();
752     let f0 = FdFlag::from_bits_truncate(fcntl(fd0, FcntlArg::F_GETFD).unwrap());
753     assert!(f0.contains(FdFlag::FD_CLOEXEC));
754     let f1 = FdFlag::from_bits_truncate(fcntl(fd1, FcntlArg::F_GETFD).unwrap());
755     assert!(f1.contains(FdFlag::FD_CLOEXEC));
756 }
757 
758 #[test]
759 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
test_truncate()760 fn test_truncate() {
761     let tempdir = tempdir().unwrap();
762     let path = tempdir.path().join("file");
763 
764     {
765         let mut tmp = File::create(&path).unwrap();
766         const CONTENTS: &[u8] = b"12345678";
767         tmp.write_all(CONTENTS).unwrap();
768     }
769 
770     truncate(&path, 4).unwrap();
771 
772     let metadata = fs::metadata(&path).unwrap();
773     assert_eq!(4, metadata.len());
774 }
775 
776 #[test]
test_ftruncate()777 fn test_ftruncate() {
778     let tempdir = tempdir().unwrap();
779     let path = tempdir.path().join("file");
780 
781     let tmpfd = {
782         let mut tmp = File::create(&path).unwrap();
783         const CONTENTS: &[u8] = b"12345678";
784         tmp.write_all(CONTENTS).unwrap();
785         tmp.into_raw_fd()
786     };
787 
788     ftruncate(tmpfd, 2).unwrap();
789     close(tmpfd).unwrap();
790 
791     let metadata = fs::metadata(&path).unwrap();
792     assert_eq!(2, metadata.len());
793 }
794 
795 // Used in `test_alarm`.
796 #[cfg(not(target_os = "redox"))]
797 static mut ALARM_CALLED: bool = false;
798 
799 // Used in `test_alarm`.
800 #[cfg(not(target_os = "redox"))]
alarm_signal_handler(raw_signal: libc::c_int)801 pub extern "C" fn alarm_signal_handler(raw_signal: libc::c_int) {
802     assert_eq!(
803         raw_signal,
804         libc::SIGALRM,
805         "unexpected signal: {}",
806         raw_signal
807     );
808     unsafe { ALARM_CALLED = true };
809 }
810 
811 #[test]
812 #[cfg(not(target_os = "redox"))]
test_alarm()813 fn test_alarm() {
814     use std::{
815         thread,
816         time::{Duration, Instant},
817     };
818 
819     // Maybe other tests that fork interfere with this one?
820     let _m = crate::SIGNAL_MTX.lock();
821 
822     let handler = SigHandler::Handler(alarm_signal_handler);
823     let signal_action =
824         SigAction::new(handler, SaFlags::SA_RESTART, SigSet::empty());
825     let old_handler = unsafe {
826         sigaction(Signal::SIGALRM, &signal_action)
827             .expect("unable to set signal handler for alarm")
828     };
829 
830     // Set an alarm.
831     assert_eq!(alarm::set(60), None);
832 
833     // Overwriting an alarm should return the old alarm.
834     assert_eq!(alarm::set(1), Some(60));
835 
836     // We should be woken up after 1 second by the alarm, so we'll sleep for 3
837     // seconds to be sure.
838     let starttime = Instant::now();
839     loop {
840         thread::sleep(Duration::from_millis(100));
841         if unsafe { ALARM_CALLED } {
842             break;
843         }
844         if starttime.elapsed() > Duration::from_secs(3) {
845             panic!("Timeout waiting for SIGALRM");
846         }
847     }
848 
849     // Reset the signal.
850     unsafe {
851         sigaction(Signal::SIGALRM, &old_handler)
852             .expect("unable to set signal handler for alarm");
853     }
854 }
855 
856 #[test]
857 #[cfg(not(target_os = "redox"))]
test_canceling_alarm()858 fn test_canceling_alarm() {
859     let _m = crate::SIGNAL_MTX.lock();
860 
861     assert_eq!(alarm::cancel(), None);
862 
863     assert_eq!(alarm::set(60), None);
864     assert_eq!(alarm::cancel(), Some(60));
865 }
866 
867 #[test]
868 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
test_symlinkat()869 fn test_symlinkat() {
870     let _m = crate::CWD_LOCK.read();
871 
872     let tempdir = tempdir().unwrap();
873 
874     let target = tempdir.path().join("a");
875     let linkpath = tempdir.path().join("b");
876     symlinkat(&target, None, &linkpath).unwrap();
877     assert_eq!(
878         readlink(&linkpath).unwrap().to_str().unwrap(),
879         target.to_str().unwrap()
880     );
881 
882     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
883     let target = "c";
884     let linkpath = "d";
885     symlinkat(target, Some(dirfd), linkpath).unwrap();
886     assert_eq!(
887         readlink(&tempdir.path().join(linkpath))
888             .unwrap()
889             .to_str()
890             .unwrap(),
891         target
892     );
893 }
894 
895 #[test]
896 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
test_linkat_file()897 fn test_linkat_file() {
898     let tempdir = tempdir().unwrap();
899     let oldfilename = "foo.txt";
900     let oldfilepath = tempdir.path().join(oldfilename);
901 
902     let newfilename = "bar.txt";
903     let newfilepath = tempdir.path().join(newfilename);
904 
905     // Create file
906     File::create(oldfilepath).unwrap();
907 
908     // Get file descriptor for base directory
909     let dirfd =
910         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
911             .unwrap();
912 
913     // Attempt hard link file at relative path
914     linkat(
915         Some(dirfd),
916         oldfilename,
917         Some(dirfd),
918         newfilename,
919         LinkatFlags::SymlinkFollow,
920     )
921     .unwrap();
922     assert!(newfilepath.exists());
923 }
924 
925 #[test]
926 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
test_linkat_olddirfd_none()927 fn test_linkat_olddirfd_none() {
928     let _dr = crate::DirRestore::new();
929 
930     let tempdir_oldfile = tempdir().unwrap();
931     let oldfilename = "foo.txt";
932     let oldfilepath = tempdir_oldfile.path().join(oldfilename);
933 
934     let tempdir_newfile = tempdir().unwrap();
935     let newfilename = "bar.txt";
936     let newfilepath = tempdir_newfile.path().join(newfilename);
937 
938     // Create file
939     File::create(oldfilepath).unwrap();
940 
941     // Get file descriptor for base directory of new file
942     let dirfd = fcntl::open(
943         tempdir_newfile.path(),
944         fcntl::OFlag::empty(),
945         stat::Mode::empty(),
946     )
947     .unwrap();
948 
949     // Attempt hard link file using curent working directory as relative path for old file path
950     chdir(tempdir_oldfile.path()).unwrap();
951     linkat(
952         None,
953         oldfilename,
954         Some(dirfd),
955         newfilename,
956         LinkatFlags::SymlinkFollow,
957     )
958     .unwrap();
959     assert!(newfilepath.exists());
960 }
961 
962 #[test]
963 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
test_linkat_newdirfd_none()964 fn test_linkat_newdirfd_none() {
965     let _dr = crate::DirRestore::new();
966 
967     let tempdir_oldfile = tempdir().unwrap();
968     let oldfilename = "foo.txt";
969     let oldfilepath = tempdir_oldfile.path().join(oldfilename);
970 
971     let tempdir_newfile = tempdir().unwrap();
972     let newfilename = "bar.txt";
973     let newfilepath = tempdir_newfile.path().join(newfilename);
974 
975     // Create file
976     File::create(oldfilepath).unwrap();
977 
978     // Get file descriptor for base directory of old file
979     let dirfd = fcntl::open(
980         tempdir_oldfile.path(),
981         fcntl::OFlag::empty(),
982         stat::Mode::empty(),
983     )
984     .unwrap();
985 
986     // Attempt hard link file using current working directory as relative path for new file path
987     chdir(tempdir_newfile.path()).unwrap();
988     linkat(
989         Some(dirfd),
990         oldfilename,
991         None,
992         newfilename,
993         LinkatFlags::SymlinkFollow,
994     )
995     .unwrap();
996     assert!(newfilepath.exists());
997 }
998 
999 #[test]
1000 #[cfg(not(any(
1001     target_os = "ios",
1002     target_os = "macos",
1003     target_os = "redox",
1004     target_os = "haiku"
1005 )))]
test_linkat_no_follow_symlink()1006 fn test_linkat_no_follow_symlink() {
1007     let _m = crate::CWD_LOCK.read();
1008 
1009     let tempdir = tempdir().unwrap();
1010     let oldfilename = "foo.txt";
1011     let oldfilepath = tempdir.path().join(oldfilename);
1012 
1013     let symoldfilename = "symfoo.txt";
1014     let symoldfilepath = tempdir.path().join(symoldfilename);
1015 
1016     let newfilename = "nofollowsymbar.txt";
1017     let newfilepath = tempdir.path().join(newfilename);
1018 
1019     // Create file
1020     File::create(&oldfilepath).unwrap();
1021 
1022     // Create symlink to file
1023     symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
1024 
1025     // Get file descriptor for base directory
1026     let dirfd =
1027         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
1028             .unwrap();
1029 
1030     // Attempt link symlink of file at relative path
1031     linkat(
1032         Some(dirfd),
1033         symoldfilename,
1034         Some(dirfd),
1035         newfilename,
1036         LinkatFlags::NoSymlinkFollow,
1037     )
1038     .unwrap();
1039 
1040     // Assert newfile is actually a symlink to oldfile.
1041     assert_eq!(
1042         readlink(&newfilepath).unwrap().to_str().unwrap(),
1043         oldfilepath.to_str().unwrap()
1044     );
1045 }
1046 
1047 #[test]
1048 #[cfg(not(any(target_os = "redox", target_os = "haiku")))]
test_linkat_follow_symlink()1049 fn test_linkat_follow_symlink() {
1050     let _m = crate::CWD_LOCK.read();
1051 
1052     let tempdir = tempdir().unwrap();
1053     let oldfilename = "foo.txt";
1054     let oldfilepath = tempdir.path().join(oldfilename);
1055 
1056     let symoldfilename = "symfoo.txt";
1057     let symoldfilepath = tempdir.path().join(symoldfilename);
1058 
1059     let newfilename = "nofollowsymbar.txt";
1060     let newfilepath = tempdir.path().join(newfilename);
1061 
1062     // Create file
1063     File::create(&oldfilepath).unwrap();
1064 
1065     // Create symlink to file
1066     symlinkat(&oldfilepath, None, &symoldfilepath).unwrap();
1067 
1068     // Get file descriptor for base directory
1069     let dirfd =
1070         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
1071             .unwrap();
1072 
1073     // Attempt link target of symlink of file at relative path
1074     linkat(
1075         Some(dirfd),
1076         symoldfilename,
1077         Some(dirfd),
1078         newfilename,
1079         LinkatFlags::SymlinkFollow,
1080     )
1081     .unwrap();
1082 
1083     let newfilestat = stat::stat(&newfilepath).unwrap();
1084 
1085     // Check the file type of the new link
1086     assert_eq!(
1087         (stat::SFlag::from_bits_truncate(newfilestat.st_mode as mode_t)
1088             & SFlag::S_IFMT),
1089         SFlag::S_IFREG
1090     );
1091 
1092     // Check the number of hard links to the original file
1093     assert_eq!(newfilestat.st_nlink, 2);
1094 }
1095 
1096 #[test]
1097 #[cfg(not(target_os = "redox"))]
test_unlinkat_dir_noremovedir()1098 fn test_unlinkat_dir_noremovedir() {
1099     let tempdir = tempdir().unwrap();
1100     let dirname = "foo_dir";
1101     let dirpath = tempdir.path().join(dirname);
1102 
1103     // Create dir
1104     DirBuilder::new().recursive(true).create(dirpath).unwrap();
1105 
1106     // Get file descriptor for base directory
1107     let dirfd =
1108         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
1109             .unwrap();
1110 
1111     // Attempt unlink dir at relative path without proper flag
1112     let err_result =
1113         unlinkat(Some(dirfd), dirname, UnlinkatFlags::NoRemoveDir).unwrap_err();
1114     assert!(err_result == Errno::EISDIR || err_result == Errno::EPERM);
1115 }
1116 
1117 #[test]
1118 #[cfg(not(target_os = "redox"))]
test_unlinkat_dir_removedir()1119 fn test_unlinkat_dir_removedir() {
1120     let tempdir = tempdir().unwrap();
1121     let dirname = "foo_dir";
1122     let dirpath = tempdir.path().join(dirname);
1123 
1124     // Create dir
1125     DirBuilder::new().recursive(true).create(&dirpath).unwrap();
1126 
1127     // Get file descriptor for base directory
1128     let dirfd =
1129         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
1130             .unwrap();
1131 
1132     // Attempt unlink dir at relative path with proper flag
1133     unlinkat(Some(dirfd), dirname, UnlinkatFlags::RemoveDir).unwrap();
1134     assert!(!dirpath.exists());
1135 }
1136 
1137 #[test]
1138 #[cfg(not(target_os = "redox"))]
test_unlinkat_file()1139 fn test_unlinkat_file() {
1140     let tempdir = tempdir().unwrap();
1141     let filename = "foo.txt";
1142     let filepath = tempdir.path().join(filename);
1143 
1144     // Create file
1145     File::create(&filepath).unwrap();
1146 
1147     // Get file descriptor for base directory
1148     let dirfd =
1149         fcntl::open(tempdir.path(), fcntl::OFlag::empty(), stat::Mode::empty())
1150             .unwrap();
1151 
1152     // Attempt unlink file at relative path
1153     unlinkat(Some(dirfd), filename, UnlinkatFlags::NoRemoveDir).unwrap();
1154     assert!(!filepath.exists());
1155 }
1156 
1157 #[test]
test_access_not_existing()1158 fn test_access_not_existing() {
1159     let tempdir = tempdir().unwrap();
1160     let dir = tempdir.path().join("does_not_exist.txt");
1161     assert_eq!(
1162         access(&dir, AccessFlags::F_OK).err().unwrap(),
1163         Errno::ENOENT
1164     );
1165 }
1166 
1167 #[test]
test_access_file_exists()1168 fn test_access_file_exists() {
1169     let tempdir = tempdir().unwrap();
1170     let path = tempdir.path().join("does_exist.txt");
1171     let _file = File::create(path.clone()).unwrap();
1172     access(&path, AccessFlags::R_OK | AccessFlags::W_OK)
1173         .expect("assertion failed");
1174 }
1175 
1176 //Clippy false positive https://github.com/rust-lang/rust-clippy/issues/9111
1177 #[allow(clippy::needless_borrow)]
1178 #[cfg(not(target_os = "redox"))]
1179 #[test]
test_user_into_passwd()1180 fn test_user_into_passwd() {
1181     // get the UID of the "nobody" user
1182     #[cfg(not(target_os = "haiku"))]
1183     let test_username = "nobody";
1184     // "nobody" unavailable on haiku
1185     #[cfg(target_os = "haiku")]
1186     let test_username = "user";
1187 
1188     let nobody = User::from_name(test_username).unwrap().unwrap();
1189     let pwd: libc::passwd = nobody.into();
1190     let _: User = (&pwd).into();
1191 }
1192 
1193 /// Tests setting the filesystem UID with `setfsuid`.
1194 #[cfg(any(target_os = "linux", target_os = "android"))]
1195 #[test]
test_setfsuid()1196 fn test_setfsuid() {
1197     use std::os::unix::fs::PermissionsExt;
1198     use std::{fs, io, thread};
1199     require_capability!("test_setfsuid", CAP_SETUID);
1200 
1201     // get the UID of the "nobody" user
1202     let nobody = User::from_name("nobody").unwrap().unwrap();
1203 
1204     // create a temporary file with permissions '-rw-r-----'
1205     let file = tempfile::NamedTempFile::new_in("/var/tmp").unwrap();
1206     let temp_path = file.into_temp_path();
1207     let temp_path_2 = temp_path.to_path_buf();
1208     let mut permissions = fs::metadata(&temp_path).unwrap().permissions();
1209     permissions.set_mode(0o640);
1210 
1211     // spawn a new thread where to test setfsuid
1212     thread::spawn(move || {
1213         // set filesystem UID
1214         let fuid = setfsuid(nobody.uid);
1215         // trying to open the temporary file should fail with EACCES
1216         let res = fs::File::open(&temp_path);
1217         let err = res.expect_err("assertion failed");
1218         assert_eq!(err.kind(), io::ErrorKind::PermissionDenied);
1219 
1220         // assert fuid actually changes
1221         let prev_fuid = setfsuid(Uid::from_raw(-1i32 as u32));
1222         assert_ne!(prev_fuid, fuid);
1223     })
1224     .join()
1225     .unwrap();
1226 
1227     // open the temporary file with the current thread filesystem UID
1228     fs::File::open(temp_path_2).unwrap();
1229 }
1230 
1231 #[test]
1232 #[cfg(not(any(
1233     target_os = "redox",
1234     target_os = "fuchsia",
1235     target_os = "haiku"
1236 )))]
test_ttyname()1237 fn test_ttyname() {
1238     let fd = posix_openpt(OFlag::O_RDWR).expect("posix_openpt failed");
1239     assert!(fd.as_raw_fd() > 0);
1240 
1241     // on linux, we can just call ttyname on the pty master directly, but
1242     // apparently osx requires that ttyname is called on a slave pty (can't
1243     // find this documented anywhere, but it seems to empirically be the case)
1244     grantpt(&fd).expect("grantpt failed");
1245     unlockpt(&fd).expect("unlockpt failed");
1246     let sname = unsafe { ptsname(&fd) }.expect("ptsname failed");
1247     let fds = open(Path::new(&sname), OFlag::O_RDWR, stat::Mode::empty())
1248         .expect("open failed");
1249     assert!(fds > 0);
1250 
1251     let name = ttyname(fds).expect("ttyname failed");
1252     assert!(name.starts_with("/dev"));
1253 }
1254 
1255 #[test]
1256 #[cfg(not(any(target_os = "redox", target_os = "fuchsia")))]
test_ttyname_not_pty()1257 fn test_ttyname_not_pty() {
1258     let fd = File::open("/dev/zero").unwrap();
1259     assert!(fd.as_raw_fd() > 0);
1260     assert_eq!(ttyname(fd.as_raw_fd()), Err(Errno::ENOTTY));
1261 }
1262 
1263 #[test]
1264 #[cfg(not(any(
1265     target_os = "redox",
1266     target_os = "fuchsia",
1267     target_os = "haiku"
1268 )))]
test_ttyname_invalid_fd()1269 fn test_ttyname_invalid_fd() {
1270     assert_eq!(ttyname(-1), Err(Errno::EBADF));
1271 }
1272 
1273 #[test]
1274 #[cfg(any(
1275     target_os = "macos",
1276     target_os = "ios",
1277     target_os = "freebsd",
1278     target_os = "openbsd",
1279     target_os = "netbsd",
1280     target_os = "dragonfly",
1281 ))]
test_getpeereid()1282 fn test_getpeereid() {
1283     use std::os::unix::net::UnixStream;
1284     let (sock_a, sock_b) = UnixStream::pair().unwrap();
1285 
1286     let (uid_a, gid_a) = getpeereid(sock_a.as_raw_fd()).unwrap();
1287     let (uid_b, gid_b) = getpeereid(sock_b.as_raw_fd()).unwrap();
1288 
1289     let uid = geteuid();
1290     let gid = getegid();
1291 
1292     assert_eq!(uid, uid_a);
1293     assert_eq!(gid, gid_a);
1294     assert_eq!(uid_a, uid_b);
1295     assert_eq!(gid_a, gid_b);
1296 }
1297 
1298 #[test]
1299 #[cfg(any(
1300     target_os = "macos",
1301     target_os = "ios",
1302     target_os = "freebsd",
1303     target_os = "openbsd",
1304     target_os = "netbsd",
1305     target_os = "dragonfly",
1306 ))]
test_getpeereid_invalid_fd()1307 fn test_getpeereid_invalid_fd() {
1308     // getpeereid is not POSIX, so error codes are inconsistent between different Unices.
1309     getpeereid(-1).expect_err("assertion failed");
1310 }
1311 
1312 #[test]
1313 #[cfg(not(target_os = "redox"))]
test_faccessat_none_not_existing()1314 fn test_faccessat_none_not_existing() {
1315     use nix::fcntl::AtFlags;
1316     let tempdir = tempfile::tempdir().unwrap();
1317     let dir = tempdir.path().join("does_not_exist.txt");
1318     assert_eq!(
1319         faccessat(None, &dir, AccessFlags::F_OK, AtFlags::empty())
1320             .err()
1321             .unwrap(),
1322         Errno::ENOENT
1323     );
1324 }
1325 
1326 #[test]
1327 #[cfg(not(target_os = "redox"))]
test_faccessat_not_existing()1328 fn test_faccessat_not_existing() {
1329     use nix::fcntl::AtFlags;
1330     let tempdir = tempfile::tempdir().unwrap();
1331     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
1332     let not_exist_file = "does_not_exist.txt";
1333     assert_eq!(
1334         faccessat(
1335             Some(dirfd),
1336             not_exist_file,
1337             AccessFlags::F_OK,
1338             AtFlags::empty(),
1339         )
1340         .err()
1341         .unwrap(),
1342         Errno::ENOENT
1343     );
1344 }
1345 
1346 #[test]
1347 #[cfg(not(target_os = "redox"))]
test_faccessat_none_file_exists()1348 fn test_faccessat_none_file_exists() {
1349     use nix::fcntl::AtFlags;
1350     let tempdir = tempfile::tempdir().unwrap();
1351     let path = tempdir.path().join("does_exist.txt");
1352     let _file = File::create(path.clone()).unwrap();
1353     assert!(faccessat(
1354         None,
1355         &path,
1356         AccessFlags::R_OK | AccessFlags::W_OK,
1357         AtFlags::empty(),
1358     )
1359     .is_ok());
1360 }
1361 
1362 #[test]
1363 #[cfg(not(target_os = "redox"))]
test_faccessat_file_exists()1364 fn test_faccessat_file_exists() {
1365     use nix::fcntl::AtFlags;
1366     let tempdir = tempfile::tempdir().unwrap();
1367     let dirfd = open(tempdir.path(), OFlag::empty(), Mode::empty()).unwrap();
1368     let exist_file = "does_exist.txt";
1369     let path = tempdir.path().join(exist_file);
1370     let _file = File::create(path.clone()).unwrap();
1371     assert!(faccessat(
1372         Some(dirfd),
1373         &path,
1374         AccessFlags::R_OK | AccessFlags::W_OK,
1375         AtFlags::empty(),
1376     )
1377     .is_ok());
1378 }
1379 
1380 #[test]
1381 #[cfg(any(
1382     all(target_os = "linux", not(target_env = "uclibc")),
1383     target_os = "freebsd",
1384     target_os = "dragonfly"
1385 ))]
test_eaccess_not_existing()1386 fn test_eaccess_not_existing() {
1387     let tempdir = tempdir().unwrap();
1388     let dir = tempdir.path().join("does_not_exist.txt");
1389     assert_eq!(
1390         eaccess(&dir, AccessFlags::F_OK).err().unwrap(),
1391         Errno::ENOENT
1392     );
1393 }
1394 
1395 #[test]
1396 #[cfg(any(
1397     all(target_os = "linux", not(target_env = "uclibc")),
1398     target_os = "freebsd",
1399     target_os = "dragonfly"
1400 ))]
test_eaccess_file_exists()1401 fn test_eaccess_file_exists() {
1402     let tempdir = tempdir().unwrap();
1403     let path = tempdir.path().join("does_exist.txt");
1404     let _file = File::create(path.clone()).unwrap();
1405     eaccess(&path, AccessFlags::R_OK | AccessFlags::W_OK)
1406         .expect("assertion failed");
1407 }
1408