summaryrefslogtreecommitdiff
path: root/test/test_unistd.rs
blob: 50af197cf2b47f1cef9234517ac07687afc92a52 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
use nix::unistd::*;
use nix::unistd::Fork::*;
use nix::sys::wait::*;
use std::ffi::CString;

#[test]
fn test_fork_and_waitpid() {
    let pid = fork();
    match pid {
      Ok(Child) => {} // ignore child here
      Ok(Parent(child_pid)) => {
          // assert that child was created and pid > 0
          assert!(child_pid > 0);
          let wait_status = waitpid(child_pid, None);
          match wait_status {
              // assert that waitpid returned correct status and the pid is the one of the child
              Ok(WaitStatus::Exited(pid_t)) =>  assert!(pid_t == child_pid),

              // panic, must never happen
              Ok(WaitStatus::StillAlive) => panic!("Child still alive, should never happen"),

              // panic, waitpid should never fail
              Err(_) => panic!("Error: waitpid Failed")
          }

      },
      // panic, fork should never fail unless there is a serious problem with the OS
      Err(_) => panic!("Error: Fork Failed")
    }
}

#[test]
fn test_getpid() {
    let pid = getpid();
    let ppid = getppid();
    assert!(pid > 0);
    assert!(ppid > 0);
}

macro_rules! execve_test_factory(
    ($test_name:ident, $syscall:ident, $unix_sh:expr, $android_sh:expr) => (
    #[test]
    fn $test_name() {
        // The `exec`d process will write to `writer`, and we'll read that
        // data from `reader`.
        let (reader, writer) = pipe().unwrap();

        match fork().unwrap() {
            Child => {
                #[cfg(not(target_os = "android"))]
                const SH_PATH: &'static [u8] = $unix_sh;

                #[cfg(target_os = "android")]
                const SH_PATH: &'static [u8] = $android_sh;

                // Close stdout.
                close(1).unwrap();
                // Make `writer` be the stdout of the new process.
                dup(writer).unwrap();
                // exec!
                $syscall(
                    &CString::new(SH_PATH).unwrap(),
                    &[CString::new(b"".as_ref()).unwrap(),
                      CString::new(b"-c".as_ref()).unwrap(),
                      CString::new(b"echo nix!!! && echo foo=$foo && echo baz=$baz"
                                   .as_ref()).unwrap()],
                    &[CString::new(b"foo=bar".as_ref()).unwrap(),
                      CString::new(b"baz=quux".as_ref()).unwrap()]).unwrap();
            },
            Parent(child_pid) => {
                // Wait for the child to exit.
                waitpid(child_pid, None).unwrap();
                // Read 1024 bytes.
                let mut buf = [0u8; 1024];
                read(reader, &mut buf).unwrap();
                // It should contain the things we printed using `/bin/sh`.
                let string = String::from_utf8_lossy(&buf);
                assert!(string.contains("nix!!!"));
                assert!(string.contains("foo=bar"));
                assert!(string.contains("baz=quux"));
            }
        }
    }
    )
);

execve_test_factory!(test_execve, execve, b"/bin/sh", b"/system/bin/sh");

#[cfg(any(target_os = "linux", target_os = "android"))]
execve_test_factory!(test_execvpe, execvpe, b"sh", b"sh");